I'm making a game with javascript canvas. I'm drawing all the game elements, like the player, blocks and lines, but I don't want you to see all that. Instead want the whole screen to be black, expect for in some places where there is lightsources. I don't need any shadows, just a circle on the screen that is lit up with a radial gradient. I am able to achieve this for one lightsource by adding a transparent gradient after I have drawn everything else, like this: (imagine the red rectangle to be all the things in the game)
//Drawing all the game elements
ctx.fillStyle = "red";
ctx.fillRect(100, 100, 400, 300);
//adding the darkness and the lightsources
var grd = ctx.createRadialGradient(150, 100, 5, 150, 100, 100);
grd.addColorStop(0, "transparent");
grd.addColorStop(1, "black");
ctx.fillStyle = grd; ctx.fillRect(0, 0, 600, 400);
JSFiddle
But how can I achieve this with multiple lightsources? The technique showed won't work.
I have tried using the Illuminated.js api, but that was incredibly slow, and I don't need anything of the shadows and all that fancy stuff, just a circle where you can see the game.
Here's an example of my approach - create black&white mask and multiply the base with it:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
//Drawing all the game elements
ctx.fillStyle = "red";
ctx.fillRect(100, 100, 400, 300);
//adding the darkness and the lightsources
function addlight(ctx, x, y) {
var grd = ctx.createRadialGradient(x, y, 10, x, y, 150);
grd.addColorStop(0, "white");
grd.addColorStop(1, "transparent");
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 600, 400);
}
var buffer = document.createElement('canvas');
buffer.width = 600;
buffer.height = 400;
b_ctx = buffer.getContext('2d');
b_ctx.fillStyle = "black";
b_ctx.fillRect(0, 0, 600, 400);
addlight(b_ctx, 150, 100);
addlight(b_ctx, 350, 200);
addlight(b_ctx, 450, 250);
ctx.globalCompositeOperation = "multiply";
ctx.drawImage(buffer, 0, 0);
<canvas id="myCanvas" width="600" height="400" style="border:1px solid #d3d3d3;">
Related
I'm trying to draw a transparent circle on the HTML Canvas. Here is the code:
const canvas = document.querySelector('#canvas');
let ctx = canvas.getContext('2d');
canvas.width = 700;
canvas.height = 700;
ctx.beginPath();
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'destination-out';
ctx.clearRect(50, 50, 200, 200);
ctx.beginPath();
ctx.fillRect(50, 50, 200, 200);
ctx.moveTo(350, 150);
ctx.beginPath();
ctx.arc(350, 150, 80, 0, 2 * Math.PI, false);
ctx.closePath();
ctx.fill();
I was able to make the rectangle transparent with globalCompositeOperation set to destination-out but it failed to make the circle fully transparent.
Here is what MDN says about destination-out operation,
The existing content is kept where it doesn't overlap the new shape.
The circle has still some opaque color applied to it. How to make it fully transparent?
Here is the live demo.
Unable to understand what's wrong with the code. Any help would be appreciated.
You are using beginpath methods but the directives you use aren't paths.
The fully transparent rectangle is created by the clearRect and not by the fillRect method.
So you should set fillStyle to white and then the code works.
const canvas = document.querySelector('#canvas');
let ctx = canvas.getContext('2d');
canvas.width = 600;
canvas.height = 400;
ctx.fillStyle = 'rgba(0, 0, 0, .5)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = 'rgba(255, 255, 255, 1)';
ctx.fillRect(25, 25, 150, 150);
ctx.arc(275, 100, 60, 0, 2 * Math.PI, false);
ctx.fill();
body {
background-color: skyblue;
position: relative;
}
img, #canvas {
position: absolute;
}
<body>
<img src="https://images.unsplash.com/photo-1635315850978-44cd0b237006?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1770&q=80" alt="" width=600 height=390>
<canvas id="canvas"></canvas>
</body>
When I change from strokeText to fillText the text disappears. I just have a gradient canvas background and I am trying to put fillText over the gradient. strokeText works fine but when I change to fillText, the text is gone.
'''
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
var grd = ctx.createRadialGradient(100, 100, 100, 100, 130, 50);
grd.addColorStop(0, "orange");
grd.addColorStop(1, "yellow");
// Fill with gradient
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 200, 100);
ctx.font="20px Georgia";
ctx.strokeText("hello",10,30);
'''
HTML
<canvas id="canvas" width="200" height="100" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML canvas tag.</canvas>
It “disappears” because you only set fillStyle once therefore both fillRect and fillText are the same gradient color. The text is there but it’s blended into the background. Change the fillStyle again before the text.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
var grd = ctx.createRadialGradient(100, 100, 100, 100, 130, 50);
grd.addColorStop(0, "orange");
grd.addColorStop(1, "yellow");
// Fill with gradient
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 200, 100);
ctx.fillStyle = "blue";
ctx.font="20px Georgia";
ctx.fillText("hello",10,30);
The reason it doesn’t do that with stroke is because stroke doesn’t get it’s orders from fillStyle so therefore it uses the default which is black.
I'm having problems making a square that has two colors in it. I found the functions createLinearGradient and addColorStop but it only fills the square with one color, which is blue.
How exactly do I fill this square properly? I'm having trouble understanding the parameters of the function it seems.
var c = canvas.getContext('2d'); // context object
var grad = c.createLinearGradient(0, 0, 0, 100);
grad.addColorStop(0, "red"); //
grad.addColorStop(1, "blue"); //
// Fill a square:
c.fillStyle = grad;
c.fillRect(100, 100, 100, 100);
fillStyles, like gradients and patterns are drawn relatively to the context's matrix, so your gradient is actually drawn above your rect:
var c = canvas.getContext('2d'); // context object
var grad = c.createLinearGradient(0, 0, 0, 100);
grad.addColorStop(0, "red"); //
grad.addColorStop(1, "blue"); //
c.fillStyle = grad;
// show the whole gradient
c.fillRect(0, 0, canvas.width, canvas.height);
// OP's square
c.strokeRect(100, 100, 100, 100);
<canvas id="canvas" height="300"></canvas>
To fix that you have two choices:
Set your gradients params correctly from the beginning:
var c = canvas.getContext('2d');
// move the y1 and y2 values by 100
var grad = c.createLinearGradient(0, 100, 0, 200);
grad.addColorStop(0, "red"); //
grad.addColorStop(1, "blue"); //
// Fill a square:
c.fillStyle = grad;
c.fillRect(100, 100, 100, 100);
<canvas id="canvas" height="300"></canvas>
Translate your context's matrix just before calling fill(). Indeed, path drawing and filling can be done on separate matrice.
var c = canvas.getContext('2d');
var grad = c.createLinearGradient(0, 0, 0, 100);
grad.addColorStop(0, "red"); //
grad.addColorStop(1, "blue"); //
c.fillStyle = grad;
// draw the path
c.rect(100, 100, 100, 100);
// change the filling matrix
c.translate(100, 100);
c.fill();
// reset the matrix
c.setTransform(1,0,0,1,0,0);
<canvas id="canvas" height="300"></canvas>
Your values for createLinearGradient were outside of the rectangle you were drawing in.
const canvas = document.getElementById('one');
const c = canvas.getContext('2d');
const grad = c.createLinearGradient(100, 100, 200, 200);
grad.addColorStop(0, "red");
grad.addColorStop(1, "blue");
c.fillStyle = grad;
c.fillRect(100, 100, 100, 100);
canvas {
outline: 1px solid black
}
<canvas id="one" width="300" height="300"></canvas>
I have these 4 layers.
What I'm trying to do is put the red and blue layer into one mask. But I don't want the purple or orange layer to be affected by this mask (only the red and blue). I manage to make it work for the orange but not for the purple layer
See my code
var canvas = document.querySelector('canvas');
canvas.height = window.innerHeight
canvas.width = window.innerWidth
var ctx = canvas.getContext('2d');
//this should'nt be affected by the mask
ctx.beginPath()
ctx.fillStyle = 'purple';
ctx.rect(0, 50, 100, 100);
ctx.fill()
//this is the mask
ctx.beginPath()
ctx.rect(10, 10, 70, 70);
ctx.fillStyle = 'green';
ctx.fill()
ctx.globalCompositeOperation = 'source-atop';
//this need to be inside the mask
ctx.beginPath()
ctx.fillStyle = 'blue';
ctx.rect(10, 10, 100, 100);
ctx.fill()
//this need to be inside the mask
ctx.beginPath()
ctx.fillStyle = 'red';
ctx.rect(50, 40, 100, 100);
ctx.fill()
ctx.globalCompositeOperation = 'source-over'; //reset
//this should'nt be affected by the mask
ctx.beginPath()
ctx.fillStyle = 'orange';
ctx.rect(200, 40, 100, 100);
ctx.fill()
And the fiddle https://jsfiddle.net/ws3b4q95/4/
Canvas doesn't know about shapes as objects, it only cares about pixels. So the purple rectangle can't be excluded from your mask, because everyting that's already drawn on the canvas, will be part of the mask.
Instead you should draw the rectangle after you've applied the mask, and use destination-over operation:
//this need to be inside the mask
ctx.beginPath()
ctx.fillStyle = 'red';
ctx.rect(50, 40, 100, 100);
ctx.fill()
//this should'nt be affected by the mask
ctx.globalCompositeOperation = 'destination-over';
ctx.beginPath()
ctx.fillStyle = 'purple';
ctx.rect(0, 40, 100, 100);
ctx.fill()
This is nice summary from Mozilla about composite operations: MDN web docs: CanvasRenderingContext2D.global .CompositeOperation
I am trying to create below canvas.
Image
my code is below. but I am having trouble to make the canvas look the like the screenshot above. can anyone help me then?
thanks though
<html>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<script>
var canvas;
var canvasContext;
window.onload = function() {
canvas = document.getElementById('gameCanvas');
canvasContext = canvas.getContext('2d');
canvasContext.fillStyle = 'blue';
canvasContext.fillRect(0,0,canvas.width,canvas.height);
canvasContext.fillStyle = 'grey';
canvasContext.fillRect(355,350,120,90);
canvasContext.fillStyle = 'grey';
canvasContext.fillRect(190,350,120,90);
canvasContext.fillStyle = 'grey';
canvasContext.fillRect(520,350,120,90);
canvasContext.fillStyle = 'grey';
canvasContext.fillRect(355,200,120,90);
canvasContext.fillStyle = 'grey';
canvasContext.fillRect(190,200,120,90);
canvasContext.fillStyle = 'grey';
canvasContext.fillRect(520,200,120,90);
}
</script>
</html>
.fillRect creates a filled region of color. However, .rect creates a "shape" that you can then use the .fill() and .stroke() methods upon.
In the below example if converted creation into a loop for brevity
var canvas;
var canvasContext;
window.onload = function() {
canvas = document.getElementById('gameCanvas');
canvasContext = canvas.getContext('2d');
canvasContext.fillStyle = 'blue';
canvasContext.fillRect(0,0,canvas.width,canvas.height);
var height = 90;
var width = 120;
var leftOffset = 190;
var topOffset = 200;
for(var x = 0; x < 6; x++){
canvasContext.beginPath();
canvasContext.rect(leftOffset,topOffset,width,height);
canvasContext.fillStyle = 'grey';
canvasContext.fill();
canvasContext.lineWidth = 4;
canvasContext.strokeStyle = 'lightblue';
canvasContext.stroke();
leftOffset += 165;
if(x === 2){
leftOffset = 190;
topOffset = 350;
}
}
}
JSFIDDLE
This tutorial on HTML5 Canvas rectangles is very handy
To add the text, you would append the following after (or before) the rect creating loop
canvasContext.beginPath();
canvasContext.font = '20pt Arial';
canvasContext.textAlign = 'center';
canvasContext.fillStyle = 'white';
canvasContext.shadowColor = 'black';
canvasContext.shadowOffsetX = 4;
canvasContext.shadowOffsetY = 4;
canvasContext.fillText('CHOOSE A SCENE TO COLOR', canvas.width/2,55);
UPDATED FIDDLE
Tutorials for text align, text shadow, and text.
Try something like this, use a function to draw a rectangle with exactly the border you want. The trick is to use .rect instead of fillRect so that you can use .stroke() immediately after.
<html>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<script>
function draw_bordered_rect(context, x, y, w, h) {
context.rect(x, y, w, h);
context.fillStyle = "grey";
context.fill();
context.lineWidth = 3;
context.strokeStyle = "lightblue";
context.stroke();
}
window.onload = function() {
canvas = document.getElementById('gameCanvas');
canvasContext = canvas.getContext('2d');
canvasContext.fillStyle = 'blue';
canvasContext.fillRect(0, 0, canvas.width, canvas.height);
canvasContext.font = '25pt Arial';
canvasContext.textAlign = 'center';
//drop shadow 2px to the left and 2px below the white text
canvasContext.fillStyle = "black";
canvasContext.fillText('CHOOSE A SCENE TO COLOR', canvas.width/2-2, 82);
//actual text ontop of the drop shadow text
canvasContext.fillStyle = 'white';
canvasContext.fillText('CHOOSE A SCENE TO COLOR', canvas.width/2, 80);
draw_bordered_rect(canvasContext, 355, 350, 120, 90);
draw_bordered_rect(canvasContext, 190, 350, 120, 90);
draw_bordered_rect(canvasContext, 520, 350, 120, 90);
draw_bordered_rect(canvasContext, 355, 200, 120, 90);
draw_bordered_rect(canvasContext, 190, 200, 120, 90);
draw_bordered_rect(canvasContext, 520, 200, 120, 90);
}
</script>
</html>
Looks like:
I have some code to design canvas box in HTML5. I think you should try this one, I hope it will help you to design your canvas box. I think you should use JavaScript mehtod context.fillRect as i am giving you Js Fidler Lind here
HTML Code
<canvas id="myCanvas" width="500" height="400">
<!-- Insert fallback content here -->
</canvas>
JavaScript Code
var canvas = $("#myCanvas");
var context = canvas.get(0).getContext("2d");
// Set rectangle and corner values
var rectX = 50;
var rectY = 50;
var rectWidth = 100;
var rectHeight = 100;
var cornerRadius = 20;
// Reference rectangle without rounding, for size comparison
context.fillRect(200, 50, rectWidth, rectHeight);
// Set faux rounded corners
context.lineJoin = "round";
context.lineWidth = cornerRadius;
// Change origin and dimensions to match true size (a stroke makes the shape a bit larger)
context.strokeRect(rectX+(cornerRadius/2), rectY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
context.fillRect(rectX+(cornerRadius/2), rectY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
// You can do the same thing with paths, like this triangle
// Remember that a stroke will make the shape a bit larger so you'll need to fiddle with the
// coordinates to get the correct dimensions.
context.beginPath();
context.moveTo(400, 60);
context.lineTo(440, 140);
context.lineTo(360, 140);
context.closePath();
context.stroke();
context.fill();
This javascript code will design canvas box just like below g]iven image