How to cut circle in the canvas element - javascript

I want to cut transparent circle from canvas rectangle which have transparency set to rgba(0,0,0,0.7). When I'm trying to cut the circle then figure path inside is grayed. Canvas is over the picture.
Expected behaviour attached.
Grayed circle figure:
Expected circle:
My JS code:
context.save()
context.fillStyle = "rgba(0,0,0,0.7)"
context.fillRect(0,0, 700, 100)
context.save()
context.globalCompositeOperation= "destination-out"
context.beginPath()
context.arc(400,100, 100, 0, 2 * Math.PI, false)
context.fill()
context.restore()

Related

Draw path - canvas

i want to draw a simple path in canvas like this:
i have allready tried (also im not sure how to create the point with a radius at 440, 400):
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(500, 0);
ctx.lineTo(440, 400);
ctx.lineTo(0, 500);
ctx.lineTo(0, 0);
ctx.fill();
but it shows me just a black 600x600 rectangle
https://jsfiddle.net/aaroniker/pmgkymch/
Thanks!
Canvas elements contain rasterized pixel data for an image of the same dimensions as those of the canvas element's width and height attributes, which default to 300 and 150 respectively. Drawing to a canvas element uses pixel coordinates of the canvas unless a context drawing transform is in effect.
Setting width and height of a canvas element in CSS scales the canvas to the dimensions set in CSS when presenting it on screen. As with scaling an ordinary image element, canvas image quality can drop noticeably if a small canvas is scaled to too large a size.
Answer A
You are seeing a black square because you drew onto a 300 x 150 pixel canvas using 600 x 600 coordinates. Filling the oversized path drawn filled in all the actual canvas pixels. The 300 x 150 pixel canvas was presented as a 600 x 600 screen area due to CSS scaling.
Answer B
The context's path drawing arcto method is used to create a rounded corner but you don't need to work out where it leaves the drawing position provided you continue by drawing a line to a known point.
In this example I've set the canvas element dimensions in HTML to 600 x 600, and scaled it to a different size (150px x 150px) in CSS
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
var radius = 100; // a number
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(500, 0);
ctx.arcTo( 440, 400, 0, 500, radius)
ctx.lineTo( 0, 500); // join end of arc to next point
ctx.lineTo(0, 0);
ctx.fill();
}
}
draw();
#canvas {
width: 150px;
height: 150px;
}
<canvas id="canvas" width="600", height="600"></canvas>
As I stated in my comment, the coordinate system gets deformed when you define canvas dimensions in CSS. Use either inline styling (as I've done) or code it into your JS. For the arc you need, use ctx.arcTo(x1, x2, y1, y2, r), where x1, y1 is the point you are arcing around (440, 400 in your case) and x2,y2 is where you want the arc to meet back up with your figure, r is the radius.
https://www.w3schools.com/tags/canvas_arcto.asp
function draw() {
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(500, 0);
ctx.lineTo(441.2, 392);
ctx.arcTo(440, 400, 431.2, 402, 8);
ctx.lineTo(0, 500);
ctx.lineTo(0, 0);
ctx.fillStyle = "#008AFF";
ctx.fill();
}
}
draw();
<canvas height="600" id="canvas" width="600"></canvas>

Transparent circles not showing up [HTML5/JavaScript]

I'm trying to draw fireflies on a canvas. I have a image of a 1x1 white pixel and I want to have a transparent circle surrounding it to simulate a glow. So far, I've managed to draw the circle, but when I try to change the global alpha of my 2d context, the image doesn't draw and neither does the circle. This has been confusing me for a while because I draw the image before I draw its surrounding circle. How can I go about fixing this?
My code:
thatBug.draw = function () {
ctx.drawImage(bugImage, thatBug.x, thatBug.y, thatBug.size, thatBug.size);
ctx.save();
ctx.globalAlpha(0.4);
ctx.beginPath();
ctx.arc(thatBug.x, thatBug.y, thatBug.size + thatBug.glowAmt, 0, 2 * Math.PI, false);
ctx.fillStyle = 'white';
ctx.fill();
ctx.restore();
};
Fixed it myself. ctx.globalAlpha(0.4) should be globalAlpha = 0.4

Create three circle mask with canvas

I need to create a circle mask with canvas, I'm trying to do that, but I can't get it.
I knew to do that with Flash, but I prefef to do without that technology:
May anybody help me with this? I don't know too much about javascript
What I need is create three circles with different sizes on a picture (Canvas with background color).
I know that you are not here to do the job of others but however much I tried I hace not gotten...
You can add as many circles as you need, you must only indicate the position and the desired radius:
JavaScript:
var context = document.getElementById('canvas').getContext('2d');
// Color of the "mask"
context.fillStyle = '#000';
// Rectangle with the proportions of the image (600x400)
context.fillRect(0,0,600,400);
/**
* #param x Specifies the x-coordinate
* #param y Specifies the y-coordinate
* #param radius Specifies radius of the circle
*/
var clearCircle = function(x, y, radius){
context.save();
context.globalCompositeOperation = 'destination-out';
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fill();
context.restore();
};
// First circle
clearCircle(155, 190, 50);
// Second circle
clearCircle(300, 190, 70);
// Third circle
clearCircle(440, 200, 60);
HTML:
<canvas id="canvas" width="600" height="400" />
CSS:
canvas{
background: url("http://cdn2.epictimes.com/derrickblair/wp-content/uploads/sites/9/2015/01/happy-people.jpg") no-repeat;
}
You can see this in action here: http://jsfiddle.net/tomloprod/szau09x6/
Related links:
You should read more about canvas here: http://www.w3schools.com/html/html5_canvas.asp

HTML 5 Canvas and Draw Circle

I am trying to understand why my circle is not in the middle of my Canvas in HTML 5.
I am trying to create a circle in the middle the canvas.
The canvas is as follows:
Canvas:
Width: 600
Height: 300
Then I draw a circle with the following code:
context.beginPath();
context.fillStyle = '#424';
context.arc(300, 150, 10, 0, 2*Math.PI, false);
context.fill();
context.closePath();
The circle is drawn inthe lower right corner.
Now if I change the (x, y) to (150, 75) then it shows in the middle.
I am just hoping someone can shed a little light on why the original code doesn't work.
You are not showing how you are setting the actual width and height of the canvas, but if the center point always is 150, 75 then the canvas is always at default size which means you are probably setting the size using css instead of directly on the element.
Try something like this:
<canvas id="myCanvas" width=600 height=300></canvas>
in JavaScript:
canvas.width = 600; // don't use canvas.style.*
canvas.height = 300;
You could also set the center this way for the arc (to make it adopt center automatically):
context.arc(context.canvas.width * 0.5, context.canvas.height * 0.5,
10, 0, 2*Math.PI, false);

Multiple light sources on canvas

I want to place a number of light sources on a background for a game I'm making, which works great with one light source as shown below:
This is achieved by placing a .png image above everything else that becomes more transperant towards the center, like this:
Works great for one light source, but I need another approach where I can add more and move the light sources around.
I have considered drawing a similar "shadow layer" pixel by pixel for each frame, and calculate the transparency depending of the distance to each light source. However, that would probably be very slow and I'm sure there are way better solutions to this problem.
The images are just examples and each frame will have considerably more content to move around and update using requestAnimationFrame.
Is there a light weight and simple way to achieve this? Thanks in advance!
Edit
With the help of ViliusL, I came up with this masking solution:
http://jsfiddle.net/CuC5w/1/
// Create canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width = 300;
canvas.height = 300;
document.body.appendChild(canvas);
// Draw background
var img=document.getElementById("cat");
ctx.drawImage(img,0,0);
// Create shadow canvas
var shadowCanvas = document.createElement('canvas');
var shadowCtx = shadowCanvas.getContext('2d');
shadowCanvas.width = canvas.width;
shadowCanvas.height = canvas.height;
document.body.appendChild(shadowCanvas);
// Make it black
shadowCtx.fillStyle= '#000';
shadowCtx.fillRect(0,0,canvas.width,canvas.height);
// Turn canvas into mask
shadowCtx.globalCompositeOperation = "destination-out";
// RadialGradient as light source #1
gradient = shadowCtx.createRadialGradient(80, 150, 0, 80, 150, 50);
gradient.addColorStop(0, "rgba(255, 255, 255, 1.0)");
gradient.addColorStop(1, "rgba(255, 255, 255, .1)");
shadowCtx.fillStyle = gradient;
shadowCtx.fillRect(0, 0, canvas.width, canvas.height);
// RadialGradient as light source #2
gradient = shadowCtx.createRadialGradient(220, 150, 0, 220, 150, 50);
gradient.addColorStop(0, "rgba(255, 255, 255, 1.0)");
gradient.addColorStop(1, "rgba(255, 255, 255, .1)");
shadowCtx.fillStyle = gradient;
shadowCtx.fillRect(0, 0, canvas.width, canvas.height);
Another way to play with light is to use the globalCompositeOperation mode 'ligther' to ligthen things, and just use globalAlpha to darken things.
First here's an image, with a cartoon lightening on the left, and a more realistic lightening on the right, but you'd rather watch the fiddle, since it's animated :
http://jsfiddle.net/gamealchemist/ABfVj/
So how i did things :
To darken :
- Choose a darkening color( most likely black, but you can choose a red or another color to teint the result).
- choose an opacity ( 0.3 seems a good start value ).
- fillRect the area you want to darken.
function darken(x, y, w, h, darkenColor, amount) {
ctx.fillStyle = darkenColor;
ctx.globalAlpha = amount;
ctx.fillRect(x, y, w, h);
ctx.globalAlpha = 1;
}
To lighten :
- Choose a lightening color. Beware that this color's r,g,b will be added to the previous point's r,g,b : if you use a high value your color will get burnt.
- change the globalCompositeOperation to 'lighter'
- you might change opacity also, to have more control over the lightening.
- fillRect or arc the area you want to lighten.
If you draw several circles while in lighter mode, the results will add up, so you can choose a quite low value and draw several circles.
function ligthen(x, y, radius, color) {
ctx.save();
var rnd = 0.03 * Math.sin(1.1 * Date.now() / 1000);
radius = radius * (1 + rnd);
ctx.globalCompositeOperation = 'lighter';
ctx.fillStyle = '#0B0B00';
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * π);
ctx.fill();
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, radius * 0.90+rnd, 0, 2 * π);
ctx.fill();
ctx.beginPath();
ctx.arc(x, y, radius * 0.4+rnd, 0, 2 * π);
ctx.fill();
ctx.restore();
}
Notice that i added a sinusoidal variation to make the light more living.
Ligthen : another way :
You can also, while still using the 'ligther' mode, use a gradient to have a smoother effect (first one is more cartoon like, unless you draw a lot of circles.).
function ligthenGradient(x, y, radius) {
ctx.save();
ctx.globalCompositeOperation = 'lighter';
var rnd = 0.05 * Math.sin(1.1 * Date.now() / 1000);
radius = radius * (1 + rnd);
var radialGradient = ctx.createRadialGradient(x, y, 0, x, y, radius);
radialGradient.addColorStop(0.0, '#BB9');
radialGradient.addColorStop(0.2 + rnd, '#AA8');
radialGradient.addColorStop(0.7 + rnd, '#330');
radialGradient.addColorStop(0.90, '#110');
radialGradient.addColorStop(1, '#000');
ctx.fillStyle = radialGradient;
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * π);
ctx.fill();
ctx.restore();
}
i also added here a sin variation.
Rq : creating a gradient on each draw will create garbage : store the gradient if you use a single gradient, and store them in an array if you want to animate the gradients.
If you are using the same light in several places, have a single gradient built, centered on (0,0), and translate the canvas before drawing always with this single gradient.
Rq 2 : you can use clipping to prevent some parts of the screen to be lightened (if there's an obstacle).
I added the blue circle on my example to show this.
So you might want to ligthen directly your scene with those effects, or create separately a light layer that you darken/lighten as you want before drawImage it on the screen.
There are too many scenari to discuss them here (light animated or not, clipping or not, pre-compute a light layer or not, ...) but as far as speed is concerned, for Safari and iOS safari, the solution using rect/arc draws -either with gradient or a solid fill- will be rocket faster than drawing an image/canvas.
On Chrome it will be quite the opposite : it's faster to draw an image than to draw each geometry when the geometry count raises.
Firefox is rather similar to Chrome for this.
your png should have full transparent corners and not transparent white in middle.
or you can draw this, but not pixel by pixel like here jsfiddle.net/pr9r7/2/
More examples: jsfiddle.net/pr9r7/3/ http://codepen.io/cwolves/pen/prvnb
Here is my Take on it:
A. Don't worry about performance until you have tried it out. The Canvas is pretty darn fast at drawing.
B. Rather than having a image with dark Corners and a Transparent middle. Why don't you try and make it more "IRL" and have the overall world be more Dark and let the light-source illuminate the Area? Highlight a small area, instead of darken everything EXCEPT a small Area.

Categories

Resources