Page is a not externally linkable
- Code, Content, and Presentation
-- JavaScript and AJAX
---- Skew Perspective of 2D Image w/ Javascript


Fotiman - 6:37 pm on Mar 12, 2012 (gmt 0)


The jsFiddle example is using jQuery. Here's the code snippet you're inquiring about:

// Find each img, and replace it with a canvas
$('img').each(function (index, el) {
var c, // new canvas which will replace this img element
ctx, // context of new canvas
i, // loop counter
tmpCtx, // temp context for doing work
h, // height of the image / new canvas
w, // width of the image / new canvas
dh, // destination height (used in translation)
dw, // destination width (used in translation)
dy, // destination y
leftTop,// left top corner position
leftBot;// left bottom corner position

// Get the height/width of the image
h = el.height;
w = el.width;

// Create the canvas and context that will replace the image
c = $("<canvas height='" + h + "' width='" + w + "'><\/canvas>");
ctx = c.get(0).getContext('2d');

// Create a temporary work area
tmpCtx = document.createElement('canvas').getContext('2d');

// Draw the image on the temp work area
for (i = 0; i < h; i++) {
dw = Math.abs((w * (h - i) + w * i) / h);
tmpCtx.drawImage(el,
0, i, w, 1, // sx, sy, sw, sh
0, i, dw, 1); // dx, dy, dw, dh
}

// Calculate the left corners to be 20% of the height
leftTop = parseInt(h * .2, 10);
leftBot = parseInt(h * .8, 10) - leftTop;

ctx.save();

// Draw the image on our real canvas
for (i = 0; i < w; i++) {
dy = (leftTop * (w - i)) / w;
dh = (leftBot * (w - i) + h * i) / w;
ctx.drawImage(tmpCtx.canvas,
i, 0, 1, h,
i, dy, 1, dh);
}

ctx.restore();

// Replace the image with the canvas version
$(el).replaceWith(c);
});


The piece that is targeting which images to change is this:

$('img').each(function (index, el) {

$('img') is jQuery terminology that will get every 'img' element. Then for each it performs the function that follows.

I would NOT recommend dropping ANY JavaScript into your web page wherever you drop the code. That suggests mixing your content layer (your HTML markup) with your behavior layer (JavaScript), which is bad practice and harder to maintain. Instead, let your content stand on its own and use progressive enhancement to add extra functionality.

Here's a modified example. Note, however, that it still relies on jQuery. If you're not using jQuery, then this will still need modification:

// Find each img, and replace it with a canvas
function skew(el) {
var c, // new canvas which will replace this img element
ctx, // context of new canvas
i, // loop counter
tmpCtx, // temp context for doing work
h, // height of the image / new canvas
w, // width of the image / new canvas
dh, // destination height (used in translation)
dw, // destination width (used in translation)
dy, // destination y
leftTop,// left top corner position
leftBot;// left bottom corner position

// Get the height/width of the image
h = el.height;
w = el.width;

// Create the canvas and context that will replace the image
c = $("<canvas height='" + h + "' width='" + w + "'><\/canvas>");
ctx = c.get(0).getContext('2d');

// Create a temporary work area
tmpCtx = document.createElement('canvas').getContext('2d');

// Draw the image on the temp work area
for (i = 0; i < h; i++) {
dw = Math.abs((w * (h - i) + w * i) / h);
tmpCtx.drawImage(el,
0, i, w, 1, // sx, sy, sw, sh
0, i, dw, 1); // dx, dy, dw, dh
}

// Calculate the left corners to be 20% of the height
leftTop = parseInt(h * .2, 10);
leftBot = parseInt(h * .8, 10) - leftTop;

ctx.save();

// Draw the image on our real canvas
for (i = 0; i < w; i++) {
dy = (leftTop * (w - i)) / w;
dh = (leftBot * (w - i) + h * i) / w;
ctx.drawImage(tmpCtx.canvas,
i, 0, 1, h,
i, dy, 1, dh);
}

ctx.restore();

// Replace the image with the canvas version
$(el).replaceWith(c);
}

var i,
imagesToSkew = document.getElementsByTagName('img'); // This is where you define which elements to replace

for (i = 0; i < imagesToSkew.length; i++) {
if (imagesToSkew[i].className && imagesToSkew[i].className == 'perspective') {
skew(imagesToSkew[i]);
}
}

In this example, I've separated the function that skews the images from the code that selects the elements. Then I'm calling that function only on the elements I want to change. In this example, I'm looking for img elements that have a 'perspective' class assigned to them. For example:

<img src="..." class="perspective">

Then I call the skew method on only those that have this class. Alternative, you could give each image a unique id and call document.getElementById(id) to get each image you want replaced (though that would be slightly harder to maintain). Then just put this script before your closing </body> tag and you're good to go.

If you're not using jQuery, then you'll need to replace the few bits from the example. The result would be this:


// Find each img, and replace it with a canvas
function skew(el) {
var c, // new canvas which will replace this img element
ctx, // context of new canvas
i, // loop counter
tmpCtx, // temp context for doing work
h, // height of the image / new canvas
w, // width of the image / new canvas
dh, // destination height (used in translation)
dw, // destination width (used in translation)
dy, // destination y
leftTop,// left top corner position
leftBot;// left bottom corner position

// Get the height/width of the image
h = el.height;
w = el.width;

// Create the canvas and context that will replace the image
//c = $("<canvas height='" + h + "' width='" + w + "'><\/canvas>");
c = document.createElement('canvas');
c.height = h;
c.width = w;
ctx = c.getContext('2d');

// Create a temporary work area
tmpCtx = document.createElement('canvas').getContext('2d');

// Draw the image on the temp work area
for (i = 0; i < h; i++) {
dw = Math.abs((w * (h - i) + w * i) / h);
tmpCtx.drawImage(el,
0, i, w, 1, // sx, sy, sw, sh
0, i, dw, 1); // dx, dy, dw, dh
}

// Calculate the left corners to be 20% of the height
leftTop = parseInt(h * .2, 10);
leftBot = parseInt(h * .8, 10) - leftTop;

ctx.save();

// Draw the image on our real canvas
for (i = 0; i < w; i++) {
dy = (leftTop * (w - i)) / w;
dh = (leftBot * (w - i) + h * i) / w;
ctx.drawImage(tmpCtx.canvas,
i, 0, 1, h,
i, dy, 1, dh);
}

ctx.restore();

// Replace the image with the canvas version
el.parentNode.replaceChild(c, el);
//$(el).replaceWith(c);
}

var i,
imagesToSkew = document.getElementsByTagName('img'); // This is where you define which elements to replace

for (i = 0; i < imagesToSkew.length; i++) {
if (imagesToSkew[i].className && imagesToSkew[i].className == 'perspective') {
skew(imagesToSkew[i]);
}
}


Then all you need to do is add class="perspective" to the images that you want to appear this way.

[edited by: Fotiman at 6:45 pm (utc) on Mar 12, 2012]


Thread source:: http://www.webmasterworld.com/javascript/4427969.htm
Brought to you by WebmasterWorld: http://www.webmasterworld.com