Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML5 Canvas - Fill circle with image

Tags:

html

canvas

How can I draw an image inside a circle? If I do:

context.beginPath();
context.arc((e.pageX),(e.pageY),161,0,Math.PI*2,true);
context.closePath();

How can I then use fill() to fill it with my drawn image?

like image 351
tbleckert Avatar asked Nov 25 '10 10:11

tbleckert


People also ask

How do I create a fill circle in HTML canvas?

Definition and Usage The arc() method creates an arc/curve (used to create circles, or parts of circles). Tip: To create a circle with arc(): Set start angle to 0 and end angle to 2*Math. PI. Tip: Use the stroke() or the fill() method to actually draw the arc on the canvas.

How do I fill a shape in HTML canvas?

To fill an HTML5 Canvas shape with a solid color, we can set the fillStyle property to a color string such as blue, a hex value such as #0000FF, or an RGB value such as rgb(0,0,255), and then we can use the fill() method to fill the shape.


4 Answers

I did this the other day for a big thing I'm making;

var thumbImg = document.createElement('img');

thumbImg.src = 'path_to_image';
thumbImg.onload = function() {
    tmpCtx.save();
    tmpCtx.beginPath();
    tmpCtx.arc(25, 25, 25, 0, Math.PI * 2, true);
    tmpCtx.closePath();
    tmpCtx.clip();

    tmpCtx.drawImage(thumbImg, 0, 0, 50, 50);

    tmpCtx.beginPath();
    tmpCtx.arc(0, 0, 25, 0, Math.PI * 2, true);
    tmpCtx.clip();
    tmpCtx.closePath();
    tmpCtx.restore();
};

Worked perfect for me.

Here's a more complex version of it that I made which does image caching too, https://jsfiddle.net/jaredwilli/ex5n5/

like image 171
jaredwilli Avatar answered Sep 24 '22 07:09

jaredwilli


Not sure if you are still looking for the answer, but here's how:

var ctx = document.getElementById('your_canvas').getContext("2d");
//ctx.lineWidth = 13; 
//ctx.strokeStyle = 'rgba(0,0,0,1)'; 
//ctx.fillStyle="rgba(0,0,0,0)" // if using this, make sure alpha < 1

ctx.arc(100,100, 50, 0, Math.PI*2,true); // you can use any shape
ctx.clip();

var img = new Image();
img.addEventListener('load', function(e) {
    ctx.drawImage(this, 0, 0, 200, 300);
    //ctx.fill();
//ctx.stroke();
}, true);
img.src="/path/to/image.jpg";

You can also do this with pattern, but you get less image placement flexibility

ctx.arc(100,100, 70, 0, Math.PI*2,true);
ctx.clip();

img = new Image()
img.addEventListener('load', function(e) {
    ctx.fillStyle = ctx.createPattern(this, 'no-repeat') 
    ctx.fill();
}, true);
img.src="/path/to/image.jpg"
like image 25
moby Avatar answered Sep 24 '22 07:09

moby


Consider using some of these alternatives:

  • Using an <img> with CSS for border-radius: http://jsfiddle.net/ChrisMorgan/BQGxA/

  • Use SVG rather than <canvas> and set the ellipse as the clipping path for an image. (More complex clipping paths are then easy, too)

Not knowing more about your requirements and situation I don't know if these will satisfy your requirements, but I think they're worth while considering. <canvas> isn't the solution to all your problems - for many of these cases, CSS in normal HMTL and/or SVG may be a better match.

like image 27
Chris Morgan Avatar answered Sep 27 '22 07:09

Chris Morgan


The problem with the clip() method is that Chrome will render the borders non antialiased, as shown in this question.

One solution is to use globalCompositeOperation as shown in Daniel's answer:

//set-up - probably only needs to be done once
var scratchCanvas = document.createElement('canvas');
scratchCanvas.width = 100;
scratchCanvas.height = 100;
var scratchCtx = scratchCanvas.getContext('2d');


//drawing code
scratchCtx.clearRect(0, 0, scratchCanvas.width, scratchCanvas.height);

scratchCtx.globalCompositeOperation = 'source-over'; //default

//Do whatever drawing you want. In your case, draw your image.
scratchCtx.drawImage(imageToCrop, ...);


//As long as we can represent our clipping region as a single path, 
//we can perform our clipping by using a non-default composite operation.
//You can think of destination-in as "write alpha". It will not touch
//the color channel of the canvas, but will replace the alpha channel.
//(Actually, it will multiply the already drawn alpha with the alpha
//currently being drawn - meaning that things look good where two anti-
//aliased pixels overlap.)
//
//If you can't represent the clipping region as a single path, you can
//always draw your clip shape into yet another scratch canvas.

scratchCtx.fillStyle = '#fff'; //color doesn't matter, but we want full opacity
scratchCtx.globalCompositeOperation = 'destination-in';
scratchCtx.beginPath();
scratchCtx.arc(50, 50, 50, 0, 2 * Math.PI, true);
scratchCtx.closePath();
scratchCtx.fill();


//Now that we have a nice, cropped image, we can draw it in our
//actual canvas. We can even draw it over top existing pixels, and
//everything will look great!

ctx.drawImage(scratchCanves, ...);
like image 34
Jesús Carrera Avatar answered Sep 26 '22 07:09

Jesús Carrera