Reusable feature for clip images into polygons using html5 canvas

Guess that a job title might be needed for editing, but so far I don't know where the problems are. I read pages and answered similar questions, here and elsewhere. One answer is especially close, but I do not understand this.

I need a function to draw polygons on the canvas in the desired coordinates and fill them with some background image loaded from a file (large enough so that there is no need for a tile). Triangles would be good for a test. Apparently, I should use drawImage and the clip, and in order to provide the polygon with the border, I can use the same path for the clip and stroke. Also, apparently, I have to keep order

- define path - save - clip - drawImage - restore - stroke. 

Also read somewhere that just uploading the image once is enough. (If you want me to quote sources for all of these assumptions, I will look for where I saw them. Most of them are in the stack overflow)

HTML is otherwise empty

 <body onload = "main ();"></body> 

The first approach, pretending that the browser will wait for the image to load:

 var ctx, img; var image_path = 'bg.jpg'; function main () { var CANVAS_SIZE = 600; var view_field_cnv = document.createElement ('canvas'); view_field_cnv.width = CANVAS_SIZE; view_field_cnv.height = CANVAS_SIZE; view_field_cnv.style.border = "1px solid"; document.body.appendChild (view_field_cnv); ctx = view_field_cnv.getContext ('2d'); img = document.createElement ('img'); img.src = image_path; place_triangle (0, 0); place_triangle (300, 300); place_triangle (500, 500); place_triangle (0, 0); } function place_triangle (x, y) { console.log (x, y); ctx.beginPath (); ctx.moveTo (x + 10, y); ctx.lineTo (x + 110, y); ctx.lineTo (x + 60, y + 40); ctx.closePath (); img = document.createElement ('img'); img.src = image_path; ctx.save (); ctx.clip (); ctx.drawImage (img, x, y); ctx.restore (); ctx.stroke (); } 

This draws all three triangles, but does not crop the image.

Second attempt, with drawImage inside image.onload:

 var ctx; var image_path = 'bg.jpg'; function main () { var CANVAS_SIZE = 600; var view_field_cnv = document.createElement ('canvas'); view_field_cnv.width = CANVAS_SIZE; view_field_cnv.height = CANVAS_SIZE; view_field_cnv.style.border = "1px solid"; document.body.appendChild (view_field_cnv); ctx = view_field_cnv.getContext ('2d'); place_triangle (0, 0); place_triangle (300, 300); place_triangle (500, 500); place_triangle (0, 0); } function place_triangle (x, y) { console.log (x, y); var img; ctx.beginPath (); ctx.moveTo (x + 10, y); ctx.lineTo (x + 110, y); ctx.lineTo (x + 60, y + 40); ctx.closePath (); img = document.createElement ('img'); img.src = image_path; img.onload = function () { ctx.save (); ctx.clip (); ctx.drawImage (img, x, y); ctx.restore (); ctx.stroke (); } } 

This picture draws a cropped image, but only one triangle, the last. Just commenting on save and restore does not help.

So, I don’t understand downloading images, saving, restoring and maybe a million other things. Where will the errors be?

+4
javascript canvas clip onload drawimage
Sep 06 '14 at 15:27
source share
1 answer

I see you already understand the basics of clipping:

  • save context, define path, clip, drawImage, restore context.

  • you can stroke after restoration if you want the stroke to slightly overlap the cropped image.

  • you can crop before cropping if you do not want the stroke to overlap the cropped image.

enter image description here

Here's a sample code and demo: http://jsfiddle.net/m1erickson/p0fup425/

 <!doctype html> <html> <head> <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css --> <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script> <style> body{ background-color: ivory; } canvas{border:1px solid red;} </style> <script> $(function(){ var canvas=document.getElementById("canvas"); var ctx=canvas.getContext("2d"); // image loader // put the paths to your images in imageURLs[] var imageURLs=[]; // push all your image urls! imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/norwayFlag.jpg"); imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/swedishFlag.jpg"); // the loaded images will be placed in images[] var imgs=[]; var imagesOK=0; loadAllImages(start); function loadAllImages(callback){ for (var i=0; i<imageURLs.length; i++) { var img = new Image(); imgs.push(img); img.onload = function(){ imagesOK++; if (imagesOK>=imageURLs.length ) { callback(); } }; img.onerror=function(){alert("image load failed");} img.crossOrigin="anonymous"; img.src = imageURLs[i]; } } function start(){ // the imgs[] array now holds fully loaded images // the imgs[] are in the same order as imageURLs[] // clip image#1 clippingPath([10,70,50,10,90,70],imgs[0],10,10); // clip image#2 clippingPath([10,170,50,110,90,170],imgs[1],10,110); // append the original images for demo purposes document.body.appendChild(imgs[0]); document.body.appendChild(imgs[1]); } function clippingPath(pathPoints,img,x,y){ // save the unclipped context ctx.save(); // define the path that will be clipped to ctx.beginPath(); ctx.moveTo(pathPoints[0],pathPoints[1]); // this demo has a known number of polygon points // but include a loop of "lineTo's" if you have a variable number of points ctx.lineTo(pathPoints[2],pathPoints[3]); ctx.lineTo(pathPoints[4],pathPoints[5]); ctx.closePath(); // stroke the path // half of the stroke is outside the path // the outside part of the stroke will survive the clipping that follows ctx.lineWidth=2; ctx.stroke(); // make the current path a clipping path ctx.clip(); // draw the image which will be clipped except in the clipping path ctx.drawImage(img,x,y); // restore the unclipped context (==undo the clipping path) ctx.restore(); } }); // end $(function(){}); </script> </head> <body> <p>Images clipped inside triangular canvas paths</p> <canvas id="canvas" width=150 height=200></canvas> <p>Original Images</p> </body> </html> 
+5
Sep 06 '14 at 16:13
source share



All Articles