Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 4039898
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 20, 20262026-05-20T12:40:47+00:00 2026-05-20T12:40:47+00:00

I have a table of canvas elements that emulates tiled image. I need to

  • 0

I have a table of canvas elements that emulates tiled image. I need to populate only those tiles that are currently visible in the viewport. Here’s the code I use

for (var ix = visibleRange.firstX; ix <= visibleRange.lastX; ix++) {
        for (var iy = visibleRange.firstY; iy <= visibleRange.lastY; iy++) {
            var canvasDispJq = $("canvas#" + frameResId + "-" + ix + "-" + iy + "-    disp");
            var canvasDisp = canvasDispJq.get(0);
            var image = new Image();
            var context = canvasDisp.getContext("2d");
            image.onload = function() {
                context.drawImage(image, 0, 0);
            }
            image.src = self.baseURL + '/' + canvasDispJq.attr("id");
        }
    }
};

But the problem is that only the last tile from the range is loaded. The same thing but implemented in this way is working fine:

$("table#canvasTable-" + frameResId + " canvas.display").each(function() {
        var canvasDispJq = $(this);
        if ((canvasDispJq.position().top + self.tileSize + imagePosition.y) > 0 &&
                (canvasDispJq.position().left + self.tileSize + imagePosition.x) > 0 &&
                (canvasDispJq.position().top + imagePosition.y) < self.containerHeight   &&
                (canvasDispJq.position().left + imagePosition.x) < self.containerWidth)   {
            var canvasDisp = canvasDispJq.get(0);
            var image = new Image();
            var context = canvasRaw.getContext("2d");
            image.onload = function() {
                context.drawImage(image, 0, 0);
            }
            image.src = self.baseURL + '/' + canvasDispJq.attr("id");
        }
});

Difference in how the visible range is calculated shouldn’t matter because I checked in Firebug and for both approaches tiles to render are selected correctly and actual tile images are downloaded from server but for first approach only last tile is displayed, while for second one all the tiles are rendered correctly.

Thanks in advance for any suggestions.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-20T12:40:48+00:00Added an answer on May 20, 2026 at 12:40 pm

    The reason for the difference is primarily here:

    var image = new Image();
    var context = canvasDisp.getContext("2d");
    image.onload = function() {
        context.drawImage(image, 0, 0);
    }
    

    What that does is create a closure and assign it to the load event of the image. The closure closes over the context and image variables (and several others). The key thing here is that it has an enduring reference to those variables, not a copy of their values when the function was created. Since the above code is in a loop, all of the functions (closures) that get created will refer to the same context and image — the last ones created by the loop.

    It doesn’t happen in the each version because in that version, the closure closes over a variable that doesn’t change, the one context and image created by the call to the iterator function you’re passing into each.

    More about closures here: Closures are not complicated

    Perhaps slightly off-topic, perhaps not: This may have been more clear if your vars were in a different place. var is sometimes misunderstood. In particular, it’s not the same as variable declarations in some other languages (C, C++, Java, and C# for instance), partially because JavaScript doesn’t have block-level scope (only function-level scope and the global scope).

    This is how the JavaScript interpreter sees your first version:

    var ix, iy, canvasDispJq, canvasDisp, image, context;
    for (ix = visibleRange.firstX; ix <= visibleRange.lastX; ix++) {
            for (iy = visibleRange.firstY; iy <= visibleRange.lastY; iy++) {
                canvasDispJq = $("canvas#" + frameResId + "-" + ix + "-" + iy + "-    disp");
                canvasDisp = canvasDispJq.get(0);
                image = new Image();
                context = canvasDisp.getContext("2d");
                image.onload = function() {
                    context.drawImage(image, 0, 0);
                };
                image.src = self.baseURL + '/' + canvasDispJq.attr("id");
            }
        }
    }
    

    Note that all the var statements have moved to the top, because that’s how they’ll be treated. Regardless of where var appears in a function, it takes effect from the very beginning of the function and only happens once. If the var has an initializer, that becomes an assignment where the var is. So var x = 2; is really two completely separate things that are handled at separate times by the interpreter: var x, which happens upon entry to the function before anything else happens, and x = 2;, which happens where it appears in the step-by-step execution of the function’s code.

    (Also, off-topic: There’s no need for a ; after the closing } of a for loop; but you do want one after the assignment to the onload handler. I’ve made both of those mods aboev as well.)

    Writing the code the way the interpreter will see it, now (to me, anyway) it’s clearer that each of the closures you’re assigning to onload will be referring to the same context and image variables, and so they’ll all see the last ones.

    If you want to use the non-each version, you just have to change it slightly so the onload closures close over their own copy of context and image. That looks like this:

    var ix, iy, canvasDispJq, canvasDisp, image, context;
    for (ix = visibleRange.firstX; ix <= visibleRange.lastX; ix++) {
            for (iy = visibleRange.firstY; iy <= visibleRange.lastY; iy++) {
                canvasDispJq = $("canvas#" + frameResId + "-" + ix + "-" + iy + "-    disp");
                canvasDisp = canvasDispJq.get(0);
                image = new Image();
                context = canvasDisp.getContext("2d");
                image.onload = createOnloadHandler(context);
                image.src = self.baseURL + '/' + canvasDispJq.attr("id");
            }
        }
    }
    
    function createOnloadHandler(ct, img) {
    
        return function() {
            context.drawImage(img, 0, 0);
        };
    }
    

    Now the closure created by the createOnloadHandler function closes over ct and img, not context and image. Each closure gets its own copy (the one passed into the createOnloadHandler call that created that closure).

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have a table in a SQL Server 2005 database with a trigger that
I have a ListView in WPF that is databound to a basic table that
I have table inside a div tab. The table has 40 rows in it
I have table with 50 entries (users with such details like Name Surname Location
I have table rows of data in html being filled from a CGI application.
Imagine I have table like this: id:Product:shop_id 1:Basketball:41 2:Football:41 3:Rocket:45 4:Car:86 5:Plane:86 Now, this
While trying to use LINQ to SQL I encountered several problems. I have table
I have a table with more than a millon rows. This table is used
I have a table story_category in my database with corrupt entries. The next query
I have a table with a structure like the following: LocationID AccountNumber long-guid-here 12345

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.