У меня есть сценарий, который ajaxes в списке изображений, то функция успеха вызова ajax открывает изображения в виде холстов, чтобы пользователь мог нарисовать наложения сверху.
В основном у меня есть for (key in data.imgs) { OpenImg(data.img[key]); }
for (key in data.imgs) { OpenImg(data.img[key]); }
вызов этого. Мне нужна высота и ширина в функции OpenImg, чтобы я мог указать размер холста.
Проблема в том, что я получаю изображения не в порядке. Моя функция img.onload необходима для задержки определения высоты/ширины, пока изображение не будет загружено.
Я выяснил, что мне нужно дождаться загрузки изображений, но также необходимо загрузить их подряд. Я могу переключить назначение идентификатора canvas из счетчика в подстроку URL-адреса, которая содержит номер страницы.
Проблема в том, что даже после переименования идентификатора canvas они не изменят порядок на экране. Есть ли хороший способ их сортировки? Могу ли я просто не присоединяться к странице, а затем использовать JQuery.each(), чтобы поместить их, но как сделать.each() запущен по id?
TL; DR: могу ли я сделать эту асинхронную функцию синхронной, не будучи фактически синхронной?
function OpenImg(url) {
var img=new Image();
img.src=url;
img.onload=function() {
$('<div/>',{'id':'_wrap_pg'+canvasCount,'class':'wrapPage','Width':img.width,'Height':img.height,'data-w':img.width,'data-h':img.height,'data-url':url}).appendTo('#filebox');
$('<canvas/>',{'id':'pg'+canvasCount,'Width':img.width,'Height':img.height,'data-w':img.width,'data-h':img.height,'data-url':url}).appendTo('#_wrap_pg'+canvasCount);
var el=document.getElementById('pg'+canvasCount);
if (typeof(G_vmlCanvasManager)!='undefined') G_vmlCanvasManager.initElement(el);
var date=new Date().getTime(); // use timestamp to force image not to cache
$('#pg'+canvasCount).css({'background-image':'url('+url+'?t='+date+')',
'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+url+"', sizingMethod='scale')",
'-ms-filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+url+"', sizingMethod='scale')"});
InitDraw(canvasCount); // function to attach events to newly created canvas
if (canvasCount==1) {
// if page 1 set zoom value to scale canvas/image to fit height
$('#zoom').val(Math.floor(100/(img.height/$('#filebox').height()))-1);
}
zoom(); // my custom zoom function
canvasCount++;
}
}
Создайте и добавьте холст на страницу как часть функции OpenImg
, а не как часть функции onload
. Вы можете сделать то же самое для <div>
. Нарисуйте небольшую иконку "загрузка" или текст, так что некоторая обратная связь для пользователя. Это гарантирует, что элементы находятся в том порядке, в котором они должны быть, независимо от порядка загрузки.
Прежде всего, я бы превратил ваш объект в массив:
var arr = [];
for (key in data.imgs) { arr.push(data.img[key]); }
Тогда я бы назвал ваш метод:
OpenImg(arr, 0);
И ваш метод будет:
function OpenImg(arr, index) {
var img=new Image();
img.src=arr[index];
img.onload=function() {
$('<div/>',{'id':'_wrap_pg'+index,'class':'wrapPage','Width':img.width,'Height':img.height,'data-w':img.width,'data-h':img.height,'data-url':url}).appendTo('#filebox');
$('<canvas/>',{'id':'pg'+index,'Width':img.width,'Height':img.height,'data-w':img.width,'data-h':img.height,'data-url':url}).appendTo('#_wrap_pg'+index);
var el=document.getElementById('pg'+index);
if (typeof(G_vmlCanvasManager)!='undefined') G_vmlCanvasManager.initElement(el);
var date=new Date().getTime(); // use timestamp to force image not to cache
$('#pg'+index).css({'background-image':'url('+url+'?t='+date+')',
'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+url+"', sizingMethod='scale')",
'-ms-filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+url+"', sizingMethod='scale')"});
InitDraw(index); // function to attach events to newly created canvas
if (index==1) {
// if page 1 set zoom value to scale canvas/image to fit height
$('#zoom').val(Math.floor(100/(img.height/$('#filebox').height()))-1);
}
zoom(); // my custom zoom function
if (index < arr.length - 1)
OpenImg(arr, ++index);
}
}
Я изменил весь ваш код "canvasCount" на индекс массива, и он будет вызывать только следующую функцию OpenImg, когда последний закончен.
setTimeout
до тех пор, пока размеры не станут ненулевыми, вместо того, чтобы использоватьonload
, потому что таким образом он может правильно определить размер как можно скорее, а затем загрузить оставшуюся часть изображения.