MaKR
MaKR

Reputation: 1892

Order HTML elements on page alphabetically by ID

I have a script that ajaxes in a list of images, then the success function of the ajax call opens the images as canvas backgrounds so the user can draw overlays on top.

Basically I have for (key in data.imgs) { OpenImg(data.img[key]); } calling this. I need height & width in the OpenImg function so that I can specify the canvas size.

The trouble is I'm getting images out of order. My img.onload function is necessary to delay the height/width detection until the image is loaded.

What I've figured out is that I need to wait for images to load, but also need to load them in succession I can switch the canvas id assignment from a counter to a substring of the URL, which contains the page number.

The problem is even after renaming the canvas id's they won't change order on screen. Is there a good way to sort these? Could I just not append to the page, then later use JQuery .each() to place them, but how to make .each() run in order by id?

TL;DR: can I make this asynchronous function seem synchronous without it actually being synchronous?

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++;
    }
}

Upvotes: 0

Views: 134

Answers (2)

Buzinas
Buzinas

Reputation: 11725

First of all, I would turn your object into an Array:

var arr = [];
for (key in data.imgs) { arr.push(data.img[key]); }

Then I would call your method:

OpenImg(arr, 0);

And your method would be:

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);
    }
}

I've changed all your "canvasCount" code to the Array's index, and it will only call the next OpenImg function when the last one has finished.

Upvotes: 0

Niet the Dark Absol
Niet the Dark Absol

Reputation: 324650

Create and append the canvas to the page as part of the OpenImg function, not as part of the onload function. You can do the same for the <div>. Draw in a little "loading" icon or text too, so there's some feedback for the user. This will ensure that the elements are in the order they should be, regardless of loading order.

Upvotes: 1

Related Questions