Hacker News new | past | comments | ask | show | jobs | submit login

in your set function for canvas, you change the fill style for each set, and you draw a full rectangle which causes an invalidation event for the browser.

i think you are taking the wrong approach.

this page shows a fast redeye removal example http://disruptive-innovations.com/zoo/demos/eyes.html

instead of operating on the canvas data, you should operate on the imageData object, which is like a buffer and will not cause an invalidation paint event.

original function

  structs.grid_canvas = function(size) {
    var canvas = document.createElement("canvas");

    canvas.width = size[0];
    canvas.height = size[1];

    var ctx = canvas.getContext("2d");

    return {
        set: function(pos, value) {
            ctx.fillStyle = 'rgb(' + value +',0,0)';
            ctx.fillRect(pos[0], pos[1], 2, 2);
        },
        get: function(pos) {
            return ctx.getImageData(pos[0], pos[1], 1, 1).data[0];
        }
    }
  }

new function

  structs.grid_imagedata = function(size) {
    var canvas = document.createElement("canvas");

    canvas.width = size[0];
    canvas.height = size[1];

    var ctx = canvas.getContext("2d");
    var imgd = ctx.getImageData(0, 0, size[0], size[1]);

    /**
    //use this to invalidate the canvas at a reasonable frame_rate
    var frame_rate = 24; //fps
    var paint_frame = setInterval( function(){

    ctx.putImageData(imgd, 0, 0);

    }, 1000/frame_rate );

    */

    return {
        set: function(pos, value) {
            var offset = (pos[1] * imgd.width + pos[0]) * 4;
            // + 0=red, 1=green,2=blue,3=alpha
            imgd.data[offset + 0]= value;
        },
        get: function(pos) {
            var offset = (pos[1] * imgd.width + pos[0]) * 4;
            // + 0=red, 1=green,2=blue,3=alpha
            return imgd.data[offset + 0];
        }
    }
  }



getImageData returns an array equivalent to grid_1d_array. The computation required to translate the 2d position (in this case 3d position as there's 4 slots per index) is what killed the performance of grid_1d_array.

Also I don't see how invalidating the canvas 24 times per second is going to help in this benchmark?


Calling fillRect is massively slower than calculating the an index in the array. As a general rule, it is more efficient to modify native data structures directly, while updating the DOM as infrequently as possible.

I understand that you may have been wanting to benchmark the actual speed of updating the canvas, but it really isn't a fair comparison with updating arrays.

Invalidating the canvas 24 times a second doesn't help with the benchmark, but it would make the example usable, in that it would actually update the canvas element on your screen.

On my computer, the example from jdavid ran in 287ms, instead of the original which ran in 7427ms.


I was trying to benchmark the actual speed of updating the canvas, in hopes that it was doing something clever behind the scenes. I can see that it's not a fair comparison, but a fair comparison is completely redundant with grid_array_1d (except a needlessly larger array).


I see your point. Thanks for posting this code - I implemented the a* pathfinding algorithm in javascript, so I looked into some of these options also. I ended up using the basic 2d structure to store the grid, since it was the most straightforward and seemed somewhat equivalent to 1d.

For a demo of it (http://briangrinstead.com/files/astar/), I used divs to represent the grid on the page, but I think it would be awesome to use the canvas grid representation since I suspect it will have much better performance than thousands of divs on the page (switch it to 100x100 to see what I mean).


that is arguably true, but the reality is that drawing that many rectangles is not the right way to use a drawing api.

i am actually really shocked that i could not find a way to do all of the draw operations on a buffer.


Is there a place I can go to find out more information like this?


For an introduction, read the section on limiting DOM manipulation here: http://www.artzstudio.com/2009/04/jquery-performance-rules/#...

Here is the Gecko DOM reference: https://developer.mozilla.org/en/DOM/element (listing common manipulation methods) https://developer.mozilla.org/en/Gecko_DOM_Reference

Basically, if you catch yourself calling DOM functions in a loop (or in a function that gets called in a loop, like the grid_canvas example here), it should be done in memory and then manipulate the DOM outside of the loop.


Do you know if there's a way to do something similar when displaying images? for a game I need to display a tiled background, and at this time I do it by looping on the x and y axis. That's slow.

Of course I then translate the resulting canvas instead of redrawing everything when I want to scroll but there's still a lot of invalidations involved.


For a tiled repeating background, I would recommend looking into createPattern function https://developer.mozilla.org/en/Canvas_tutorial/Applying_st....

You can use code like this:

    context.fillStyle = context.createPattern(img, 'repeat');
    context.fillRect(0, 0, 100, 100);
Where 'img' is an Image object you loaded from an src, or even a canvas object that you may have used to build a composite background.

If this doesn't work in your situation, I would at least build this image once in a canvas in memory (using document.createElement), and reference it in the 'drawImage' function instead of building it from scratch each time. Though it sounds like you might already be doing this. Do you have a link to your game?




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: