How to use: globalCompositeOperation on multiple objects in JavaScript Canvas - javascript

I'm attempting to create a circle menu in JavaScript canvas, something that would look similar to this:
Here is the code I'm using:
let canvas = document.querySelector("#canvas");
canvas.width = 500;
canvas.height = 500;
let ctx = canvas.getContext("2d");
ctx.fillStyle = "rgba(0,0,0,.45)"; // color
let circlePath = [];
let centerCircle = new Path2D();
for (let t = 0; t < 8; t++) {
circlePath[t] = new Path2D();
circlePath[t].moveTo(250, 250);
circlePath[t].arc(
250,
250,
190,
Math.PI * 2 * 0.125 * t,
Math.PI * 2 * 0.125 * t + Math.PI * 2 * 0.1175
);
circlePath[t].closePath();
ctx.fill(circlePath[t]);
}
ctx.fillStyle = "#fff";
centerCircle.moveTo(250, 250);
centerCircle.arc(250,250,100,0,2*Math.PI);
ctx.fill(centerCircle);
canvas.addEventListener("mousemove", function (event) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let t = 0; t < 8; t++) {
if (ctx.isPointInPath(circlePath[t], event.offsetX, event.offsetY)) {
ctx.fillStyle = "blue";
} else {
ctx.fillStyle = "rgba(0,0,0,.45)";
}
ctx.fill(circlePath[t]);
}
ctx.fillStyle = "#fff";
centerCircle.moveTo(250, 250);
centerCircle.arc(250,250,100,0,2*Math.PI);
//ctx.globalCompositeOperation = "destination-out";
ctx.fill(centerCircle);
});
#canvas {
border: 1px solid #000;
background: green;
};
<canvas id="canvas"></canvas>
The problem I am having is that when I try to use ctx.globalCompositeOperation = "destination-out"; to "punch out" a hole in the midle of the arcs using the white circle, it makes all of the objects disappear.
Thank you in advance for any input provided.

Figured it out! Had to place ctx.globalCompositeOperation = "destination-out"; in the right places, followed by: ctx.globalCompositeOperation = "source-over";
Here is the updated code:
let canvas = document.querySelector("#canvas");
canvas.width = 500;
canvas.height = 500;
let ctx = canvas.getContext("2d");
ctx.fillStyle = "rgba(0,0,0,.45)"; // color
let circlePath = [];
let centerCircle = new Path2D();
for (let t = 0; t < 8; t++) {
circlePath[t] = new Path2D();
circlePath[t].moveTo(250, 250);
circlePath[t].arc(
250,
250,
190,
Math.PI * 2 * 0.125 * t,
Math.PI * 2 * 0.125 * t + Math.PI * 2 * 0.1175
);
circlePath[t].closePath();
ctx.fill(circlePath[t]);
}
ctx.fillStyle = "#fff";
centerCircle.moveTo(250, 250);
centerCircle.arc(250,250,100,0,2*Math.PI);
ctx.globalCompositeOperation = "destination-out";
ctx.fill(centerCircle);
ctx.globalCompositeOperation = "source-over";
canvas.addEventListener("mousemove", function (event) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let t = 0; t < 8; t++) {
if (ctx.isPointInPath(circlePath[t], event.offsetX, event.offsetY)) {
ctx.fillStyle = "blue";
} else {
ctx.fillStyle = "rgba(0,0,0,.45)";
}
ctx.fill(circlePath[t]);
}
ctx.fillStyle = "#fff";
centerCircle.moveTo(250, 250);
centerCircle.arc(250,250,100,0,2*Math.PI);
ctx.globalCompositeOperation = "destination-out";
ctx.fill(centerCircle);
ctx.globalCompositeOperation = "source-over";
});
#canvas {
border: 1px solid #000;
background: green;
};
<canvas id="canvas"></canvas>

Related

Aligning text inside rectangle of html5 canvas

I have resizable rectangle, and I wish to have right-aligned text (day numbers) next to it.
what I have now:
(also when resizing the text does not really align vertically)
what I wish to have:
Is there a way to fill the text and align it inside a drawn rectangle? Other suggestions are welcome too.
js.do code
function dayRect(day) {
const days = ["I","II","III","IV","V","VI","VII"];
context.beginPath();
//maybe align the text inside this rect somehow
context.rect(0, day*h/7, 3*w/27, h/7);
context.stroke();
context.font = "0.5rem Arial";
context.fillStyle = "#fff";
context.fillText(days[day], 0, (day+1)*h/7);
}
I've changed a few things in your code since I wasn't able to see anything. You need to use context.textAlign="right" for your text and move it to a different position. I hope it helps.
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
var canvas = document.getElementById("posHourCanvas");
var context = canvas.getContext('2d');
canvas.width=600,canvas.height=300;
var boxes = [];
function init() {
context.clearRect(0, 0, canvas.width, canvas.height);
boxes.length = 0;
const strokeWidth = 0.6;
//canvas.width = $('#two')[0].clientWidth;
var cellSize = canvas.width/27;
canvas.height = 7/27 * canvas.width;
var x = y = 0;
draw(x,y,canvas.width,canvas.height,cellSize,strokeWidth);
}
function Box(x, y, day, hour) {
this.x = x;
this.y = y;
this.day = day;
this.hour = hour;
}
function draw(x, y, w, h, cellSize, strokeWidth) {
let onePixel = cellSize * strokeWidth;
cellSize = cellSize * (1 - strokeWidth);
context.beginPath();
context.lineWidth = 1;
context.strokeStyle = 'rgba(0, 0, 0, 1)';
const rectCoordinates = {
x: x+3*w/27,
y: y,
w: w-3*w/27,
h: h
}
context.rect(rectCoordinates.x, y, rectCoordinates.w, h);
context.fillStyle = 'white';
context.fill();
context.stroke();
let offX = rectCoordinates.w/24 + rectCoordinates.x;
let offY = h/7;
for (let i = 0; i < 7; i++) {
dayRect(i);
context.beginPath();
context.moveTo(0, offY);
context.lineTo(w, offY);
context.strokeStyle = "black";
context.stroke();
offY+=h/7;
}
for (let i = 0; i < 24; i++) {
context.beginPath();
context.moveTo(offX, 0);
context.lineTo(offX, h);
context.stroke();
offX+=rectCoordinates.w/24;
}
function dayRect(day) {
const days = ["I","II","III","IV","V","VI","VII"];
context.beginPath();
context.rect(0, day*h/7, 3*w/27, h/7);
context.stroke();
context.font = "0.5rem Arial";
context.fillStyle = "#fff";
context.textAlign="right";
context.fillText(days[day], 60, (day+1)*h/7);
}
}
init();
body {
margin: auto;
color: white;
background-color: black;
min-height: 100vh;
}
<div id="parent">
<div>text above</div>
<div id="two">
<canvas id="posHourCanvas" width="600" height="300"></canvas>
</div>
<div>text under</div>
</div>

How to change the color of the circle on canvas every n seconds?

How could the size of the shadow change, every n seconds? I guess you have to constantly create a new circle and eliminate the previous one? How would this be done? And also, is not there a more optimal way?
function main() {
var canvas = document.getElementsByTagName("CANVAS")[0],
ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = document.documentElement.scrollHeight;
var cW = canvas.width,
cH = canvas.height;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, cW, cH);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "#FFF";
ctx.shadowBlur = 5;
ctx.shadowColor = "#FFF";
ctx.arc(cW/2, cH/2, 50, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
}
window.addEventListener("load", main);
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<canvas></canvas>
</body>
</html>
Create a setInterval & an array of colors. Use Math.random to randomly select any color.
Modify the main function to accept colors as two parameters.
function main(bckColor, circleColor) {
var canvas = document.getElementsByTagName("CANVAS")[0],
ctx = canvas.getContext("2d");
if (canvas.height) {
canvas.height = 0;
}
canvas.width = window.innerWidth;
canvas.height = document.documentElement.scrollHeight;
var cW = canvas.width,
cH = canvas.height;
ctx.fillStyle = bckColor || "#000";
//ctx.fillStyle = "red" ;
ctx.fillRect(0, 0, cW, cH);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = circleColor || "#FFF";
ctx.shadowBlur = 5;
ctx.shadowColor = "#FFF";
ctx.arc(cW / 2, cH / 2, 50, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
}
var colorArray = ['red', 'green', 'yellow', 'blue', 'pink', 'brown', 'orange']
var changeColor = setInterval(function() {
let bckColor = colorArray[Math.floor(Math.random() * 7 + 1)];
let circleColor = colorArray[Math.floor(Math.random() * 7 + 1)];
main(bckColor, circleColor)
}, 2000)
window.addEventListener("load", main);
<canvas></canvas>
instead of animating the canvas itself with a redraw every x seconds, i would suggest using an overlay , create a circle div, position it over the canvas' circle and animate its shadow using css, you'll have all the controls you want like the shadow's color and distance, animation speed ..etc.
here's a fiddle ( the overlay is better positionned )
function main() {
var canvas = document.getElementsByTagName("CANVAS")[0],
ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = document.documentElement.scrollHeight;
var cW = canvas.width,
cH = canvas.height;
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, cW, cH);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "#FFF";
ctx.shadowBlur = 5;
ctx.shadowColor = "#FFF";
ctx.arc(cW / 2, cH / 2, 50, 0, 2 * Math.PI, false);
ctx.fill();
ctx.closePath();
// position the overlay over the circle
overlay.style.top = (cH / 2 - 99) + 'px'
overlay.style.left = (cW / 2 - 50) + 'px'
}
window.addEventListener("load", main);
main()
const animationDuration = 2;
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
overlay.style.animationDuration = animationDuration + 's';
setInterval(function() {
overlay.style.color = getRandomColor()
}, animationDuration * 1000)
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
canvas {
width: 100vw;
height: 100vh;
display: block;
}
#overlay {
border-radius: 50%;
background: none;
animation: shadow linear infinite;
margin: auto;
transform: translate(0, 50%);
color: green;
position: absolute;
z-index: 99;
width: 100px;
height: 93px;
}
#keyframes shadow {
0% 100% {
box-shadow: 0 0 0
}
50% {
box-shadow: 0 0 50px 20px
}
}
<canvas></canvas>
<div id="overlay">
</div>

populating more type of similar objects in canvas

I have a canvas,I am using it to draw balls.However I want to populate balls from 1 to say 10 balls at random space within the canvas.Should i use 10 seperate functions(drawBall1(),drawBall2,....,drawBall10)?
OR
Are there any other methods?
var canvas = document.getElementById("myCanvas");
var ballRadius = 10;
var ctx = canvas.getContext("2d");
function draw() {
drawBall();
}
function drawBall() {
ctx.beginPath();
ctx.arc(Math.random() * canvas.width, Math.random() * canvas.height, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = "green";
ctx.fill();
}
draw();
canvas {
background: #eee;
display: block;
margin: 0 auto;
}
<canvas id="myCanvas"></canvas>
You can just call that one function ten times instead of creating ten functions which do the same thing or you could introduce a loop inside which loops 10 times for you, depedning on what suits you better.
I hope I understood your question correctly.
function drawBall(x, y, radius, color, ctx)
{
ctx.beginPath()
ctx.arc(x, y, radius, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
}
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
var x, y, color,
colors = ['#ffc0cb', '#008080', '#b0e0e6', '#003366', '#666666', '#faebd7'],
radius = 10,
ballCount = 10;
for (var i = 0; i < ballCount; i++)
{
x = Math.floor(Math.random() * (canvas.width + 1));
y = Math.floor(Math.random() * (canvas.height + 1));
color = colors[Math.floor(Math.random() * colors.length)];
drawBall(x, y, radius, color, ctx);
}
<canvas width="200px" height="200px" id="canvas" style="border: 1px solid black"></canvas>
You can create object that describe the ball and has functions that can draw or other behaviours
var ctx = canvas.getContext("2d");
function createBall(x,y,radius,color){
return { // return a new ball
x,y,radius,color, // set the balls properties
draw(ctx){ // add a draw function
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fill();
return this; // to allow chaining
},
}
}
const colors = "#C30A4C,#CCAB7C,#CC984B,#DE880C,#546D84,#7F858A,#697785,#375E85,#125290,#94B870";
const ballRadius = 20;
const rand = (size)=>{return Math.floor(Math.random() * size)}; // rand util
const balls = []; // an array to hold the balls
balls.push( // add some balls to the ball array
...colors
.split(",")
.map(color=>createBall(
rand(ctx.canvas.width),
rand(ctx.canvas.height),
ballRadius,
color
))
)
balls.forEach(ball=>ball.draw(ctx)); // draw them.
<canvas id="canvas" width=512 height=200></canvas>

DrawImage() doesn't draw on canvas

I am trying to make a screen following the player so that the player is in the middle of the screen. I have already made it in another game, but here it doesn't work. Here is my code :
var c = document.getElementById("main");
var ctx = c.getContext("2d");
var screen = document.getElementById("screen").getContext("2d");
var WhatUSeeWidth = document.getElementById("screen").width;
var WhatUSeeHeight = document.getElementById("screen").height;
ctx.beginPath();
for (i = 0; i < 100; i ++) {
if (i % 2) {
ctx.fillStyle = "red";
}
else {
ctx.fillStyle = "blue";
}
ctx.fillRect(0, i * 100, 500, 100);
}
var player = {
x : 700,
y : 800
}
setInterval(tick, 100);
function tick() {
screen.beginPath();
screen.drawImage(c, player.x - WhatUSeeWidth / 2, player.y - WhatUSeeHeight / 2, WhatUSeeWidth, WhatUSeeHeight, 0, 0, WhatUSeeWidth, WhatUSeeHeight);
}
canvas {
border: 2px solid black;
}
<canvas id="main" width="500" height="500"h></canvas>
<canvas id="screen" width="500" height="500"></canvas>
I want to draw The Blue and red canvas in The "screen" canvas Using drawImage
Ok , from your comment I understood what you are looking for. But the problem is that you probably start by an example without having understood. I try to give you my interpretation of what you do , but you should look for a good guide that starts with the basics and deepen animations (for example this: http://www.html5canvastutorials.com/).
HTML
<canvas id="canvasLayer" width="500" height="500"></canvas>
Javascript
var canvas = document.getElementById("canvasLayer");
var context = canvas.getContext("2d");
var WhatUSeeWidth = document.getElementById("canvasLayer").width;
var WhatUSeeHeight = document.getElementById("canvasLayer").height;
var player = {
x : 0,
y : 0
}
function drawBackground() {
for (i = 0; i < 100; i ++) {
if (i % 2) {
context.fillStyle = "red";
}
else {
context.fillStyle = "blue";
}
context.fillRect(0, i * 100, 500, 100);
}
}
function playerMove() {
context.beginPath();
var radius = 5;
context.arc(player.x, player.y, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 1;
context.strokeStyle = '#003300';
context.stroke();
}
setInterval(tick, 100);
function tick() {
context.clearRect(0, 0, canvas.width, canvas.height);
drawBackground();
player.x++;
player.y++;
playerMove();
}
This is the JSFiddle.
EDIT WITH THE CORRECT ANSWER
The error is in the position of the object "player". It is located outside of the canvas, width:500 height:500 and the "player" is in position x:700 y:800.
Changing the position of the player your copy will appear.
var player = {
x : 50,
y : 50
}
Here the jsfiddle example.

Set attributes of HTML canvas arc

I'm still new to HTML5 and canvas. I'm setting points on a canvas as such:
var ctx = canvas.getContext("2d");
for (var i = 0; i < 500; i++) {
ctx.fillStyle = 'rgba(255,255,255,0.2)';
ctx.beginPath();
ctx.arc(points[i].x, points[i].y, radius, 0, Math.PI * 2, true);
ctx.fill();
}
Is there a way such that once the canvas is drawn, when I look for say, "200", I can identify the particular dot and change its color? Or would it be better to redraw the entire canvas?
var canvas, ctx, points;
var radius = 10;
var num = 20;
$(function () {
points = [];
for (var i = 0; i < num; i++) {
points.push({
x: Math.random() * 300 >> 0,
y: Math.random() * 200 >> 0
});
}
canvas = document.getElementById('canvas');
ctx = canvas.getContext("2d");
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, 300, 200);
for (var i in points) {
ctx.fillStyle = 'rgba(255,255,255,0.8)';
ctx.beginPath();
ctx.arc(points[i].x, points[i].y, radius, 0, Math.PI * 2, true);
ctx.fill();
}
});
var initrand = Math.random() * num >> 0;
function change() {
var random = initrand;
ctx.fillStyle = '#234263';
ctx.beginPath();
ctx.arc(points[random].x, points[random].y, radius, 0, Math.PI * 2, true);
ctx.fill();
initrand = Math.random() * num >> 0;
}
Demo for above Code

Categories

Resources