Using JQuery live() with find()

Hi guys,

I have the following code which is drawing a canvas on each element on the page but it is in a CMS and the elements are being added dynamically which means that the element is not always there when JQuery parses the DOM. My error says “ctx is not defined” but it does render some of the canvas elements so I know it is defined at some points.

I know I am supposed to use live() or delegate but I have only done it with click handlers before and I’m not sure of the exact syntax in this instance. Can anyone help me?


if (isCanvasSupported())
{
$(".price_canvas_replace").hide();

$('.wrap_link').each(function() {

 ctx = $(this).find('.html5_price');

var element = ctx.get(0);


 ctx=element.getContext("2d");

ctx.beginPath();
ctx.arc(35,35,35,0,Math.PI*2,true);
ctx.closePath();
var grd=ctx.createRadialGradient(35,35,35,0,Math.PI*2,true);
grd.addColorStop(0,"#8ED6FF");
grd.addColorStop(1,"#004CB3");
 ctx.fillStyle= grd;
ctx.fill();
   i++;


});
}

You would only use .live() and .delegate() for event handling :wink:

If you want to code this in a slightly more defensive way, you could simply check what ctx is before using it.

e.g.

if ( isCanvasSupported() ) { 

    $(".price_canvas_replace").hide();
 
    var i = 0;
 
    $('.wrap_link').each(function() {
 
        ctx = $(this).find('.html5_price');
 
        //check to make sure ctx has at least one element 
        if (ctx.length == 0) {
            return false;
        }
 
        var element = ctx.get(0);
 
        //should probably do a check here to make sure 'element' is a canvas element
 
        ctx=element.getContext("2d");

        ctx.beginPath();
        ctx.arc(35,35,35,0,Math.PI*2,true);
        ctx.closePath();

        var grd=ctx.createRadialGradient(35,35,35,0,Math.PI*2,true);

        grd.addColorStop(0,"#8ED6FF");
        grd.addColorStop(1,"#004CB3");
        ctx.fillStyle= grd;
        ctx.fill();
        i++;
    });
}

In addition to this, if you were to call this code only after the DOM has loaded - after the CMS has inserted its content - then you will know that at least all .wrap_link items are present. (Unless of course your CMS is injecting content via AJAX).

Try using jQuery’s $(document).ready(function() { /* your code */ }); to make sure the code you run will only do so when the DOM is ready.

Hi John,

Thanks for the clarification over event handlers and live/delegate.

Unfortunately I am using document ready, the full code is below. I am using HTML5 to draw circular placeholders behind the prices of my e-commerce store and this means that if one of the canvas elements is not present in the DOM at the time of pageload or refresh, the canvas isn’t drawn and the price appearance is all messed up.

I must also mention that it renders ok in most browsers even on croaky old IE 7 but not with Firefox which is a problem. When you refresh the page with FF some of the prices are there and others aren’t , looks really unsightly. That tells me that some of the 24 instances of canvas aren’t loading quick enough. I am unable to use one big canvas either because every product is in a different table cell and will have varying widths and heights.

I really want to suport HTML5 but it would seem that canvas just doesn’t render quick enough if you have multiple instances (inot as many as 24 at any rate) :(.

Anyway, maybe I am creating some huge overhead that I don’t know of:



$(document).ready(function(){

	$("#content a img, #content_home a img").hover(function() {
		$(this).stop()
		.animate({opacity: 0.7}, "medium")

	}, function() {
		$(this).stop()
		.animate({opacity: 1}, "medium")
	});

function isCanvasSupported(){
  var elem = document.createElement('canvas');
  return !!(elem.getContext && elem.getContext('2d'));
}


 
 var i = 0;
 var c;
 var ctx ;
if (isCanvasSupported())
{
$(".price_canvas_replace").hide();

$('.wrap_link').each(function() {

 ctx = $(this).find('.html5_price');

var element = ctx.get(0);

  
 ctx=element.getContext("2d");

ctx.beginPath();
ctx.arc(35,35,35,0,Math.PI*2,true);
ctx.closePath();
var grd=ctx.createRadialGradient(35,35,35,0,Math.PI*2,true);
grd.addColorStop(0,"#8ED6FF");
grd.addColorStop(1,"#004CB3");
 ctx.fillStyle= grd;
ctx.fill();
   i++;

   
});
}



});

OK so what I was doing there was a little overkill, I was searching inside the class wrap_link for the class html5_price so I just did:


$('.html5_price').each(function() {

 ctx = $(this);

Now it loads in plenty of time. In this situation I am using the E-commerce CMS opencart which loads up tLOTS of different scripts on this particular page so its not surprising that I was maxing out the browser by doing an additional find() inside the each() function.

I am sure that HTML5 canvas is more than adequate speed-wise but I have read somewhere that one of the ways to combat speed issues when rendering multiple canvases is to round up/down your co-ordinates, not applicable in this situation but in case anyone is reading this post with optimizing canvas performance in mind. :wink:

Regardless of using it I have concluded that HTML5 and is always going to be faster than loading an equivalent image although not always idea, it should be at the developer’s discretion whether to use images or HTML5.