Fade in items individually on a canvas - javascript

I would like to animate individual rectangles. I am trying to Fade In a rectangle independently. I want to create FadeIn(rectangle) and FadeOut(Rectangle) functions where I can pass a rectangle to fade in individual items.
I have seen https://codepen.io/mattsrinc/pen/YzPZbWw however, that's having multiple render loops, changing colors,etc. I am trying to make only FadeIn and FadeOut functions.
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var i = 0;
requestAnimationFrame(test);
requestAnimationFrame(test1);
function test() {
i += 0.002;
i = i < 0 ? 0 : i;
ctx.globalAlpha = 1;
ctx.fillStyle = "white";
ctx.fillRect(20, 20, 75, 50);
ctx.globalAlpha = i;
ctx.fillStyle = "red";
ctx.fillRect(20, 20, 75, 50);
requestAnimationFrame(test);
}
function test1() {
i += 0.002;
i = i < 0 ? 0 : i;
ctx.globalAlpha = 1;
ctx.fillStyle = "white";
ctx.fillRect(100, 60, 75, 50);
ctx.globalAlpha = i;
ctx.fillStyle = "blue";
ctx.fillRect(100, 60, 75, 50);
requestAnimationFrame(test1);
}

You only need one requestAnimationFrame, use clearRect instead of drawing a white rect, clamp the alpha value between 0 and 1 so you won't get weird flickering.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var blueAlpha = 0;
var blueSetp = 0.02; // Blue velocity
var redAlpha = 0;
var redStep = 0.01; // Red velocity
const calmp = (value, min, max) => Math.max(min, Math.min(value, max));
requestAnimationFrame(render);
function render() {
// Setting Blue Alpha
if(blueAlpha < 0 || blueAlpha > 1)
blueSetp = blueSetp * -1; // inverse blue
blueAlpha += blueSetp;
// Drawing Blue
ctx.globalAlpha = calmp(blueAlpha, 0, 1);
ctx.fillStyle = "blue";
ctx.clearRect(100, 60, 75, 50); // Use clearRect
ctx.fillRect(100, 60, 75, 50);
// Setting Red alpha
if(redAlpha < 0 || redAlpha > 1)
redStep = redStep * -1; // inverse red
redAlpha += redStep;
// Drawing Red
ctx.globalAlpha = calmp(redAlpha, 0, 1);
ctx.fillStyle = "red";
ctx.clearRect(20, 20, 75, 50);
ctx.fillRect(20, 20, 75, 50);
requestAnimationFrame(render);
}
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>

Related

how to make a row of triangles using loops?

How do I make a row of triangles?
Here's the code I have so far.
I'm new I don't know what to do here.
function showDrawing() {
let coolCanvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
ctx.lineWidth = 5;
for (let i = 0; i < 5; i += 1) {
ctx.beginPath();
ctx.moveTo(126, 300);
ctx.lineTo(200, 400);
ctx.lineTo(50, 400);
ctx.closePath();
ctx.strokeStyle = 'blue';
ctx.fillStyle = 'purple';
ctx.fill();
ctx.stroke();
}
}
<canvas id="canvas" width="1500" height="700" style="border:3px solid #000000;">
</canvas>
<button onclick="showDrawing()">Drawing</button>
You can use the iteration (i) and multiply it by the spacing you want and add it to the x value.
function showDrawing() {
let coolCanvas = document.getElementById("canvas");
let ctx = coolCanvas.getContext("2d");
ctx.lineWidth = 5;
for (let i = 0; i < 5; i += 1) {
ctx.beginPath();
ctx.moveTo(126+(i*170), 300);
ctx.lineTo(200+(i*170), 400);
ctx.lineTo(50+(i*170), 400);
ctx.closePath();
ctx.strokeStyle = 'blue';
ctx.fillStyle = 'purple';
ctx.fill();
ctx.stroke();
}
}
<canvas id="canvas" width="1500" height="700" style="border:3px solid #000000;">
</canvas>
<button onclick="showDrawing()">Drawing</button>
You should use a variable to add to the X positions and increment as you want :
function showDrawing() {
let coolCanvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
let delta = 0;
ctx.lineWidth = 5;
for (let i = 0; i < 5; i += 1) {
ctx.beginPath();
ctx.moveTo(126 + delta, 300);
ctx.lineTo(200 + delta, 400);
ctx.lineTo(50 + delta, 400);
ctx.closePath();
ctx.strokeStyle = 'blue';
ctx.fillStyle = 'purple';
ctx.fill();
ctx.stroke();
delta += 174;
}
}
<canvas id="canvas" width="1500" height="700" style="border:3px solid #000000;">
</canvas>
<button onclick="showDrawing()">Drawing</button>
You can create a separate function to handle drawing the triangles, then pass in the xStart as the base x-coordinate value for any triangle to be drawn. Then in the showDrawing function, run a loop and multiply the i variable to some spacing value. In your code, your triangle is 150 pixels wide and starts at x-value of 50, so I multiplied the i value by 200 for consistency in my solution code.
Additionally, I highly advise using the variable name you set (coolCanvas) as the reference to the canvas or set this variable to be named canvas instead. If you only ever set the canvas once and reference it once, you can probably skip setting the reference altogether:
let ctx = document.getElementById("canvas").getContext("2d");
function drawTriangle(ctx, xStart) {
ctx.lineWidth = 5;
ctx.strokeStyle = "blue";
ctx.fillStyle = "purple";
ctx.beginPath();
ctx.moveTo(xStart + 126, 300);
ctx.lineTo(xStart + 200, 400);
ctx.lineTo(xStart + 50, 400);
ctx.closePath();
ctx.fill()
ctx.stroke();
}
function showDrawing() {
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
ctx.lineWidth = 5;
for (let i = 0; i < 5; i += 1) {
drawTriangle(ctx, i * 200);
}
}
document.getElementById("draw").addEventListener("click", showDrawing);
canvas {
border: 3px solid #000000;
}
<div><button id="draw">Drawing</button></div>
<div><canvas id="canvas" width="1500" height="700"></canvas></div>

How to remove intersection of two transparent shapes on canvas?

I want to remove the intersection of two shapes, I understand that to do this I can use the XOR operation. the problem is that I need these two shapes to be transparent. By making the two shapes transparent the intersection is not eliminated.
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "red";
ctx.fillRect(20, 20, 75, 50);
ctx.fillStyle = "blue";
ctx.globalCompositeOperation = "xor";
ctx.fillRect(50, 50, 75, 50);
ctx.fillStyle = "rgba(255,0,0,0.5)";
ctx.fillRect(150, 20, 75, 50);
ctx.fillStyle = "rgba(40,23,0,0.5)";
ctx.globalCompositeOperation = "xor";
ctx.fillRect(180, 50, 75, 50);
</script>
</body>
</html>
Note: In the real problem it is not possible for me to generate an image, as proposed here
A simple (possibly simplistic, but it works) way of clearing pixels in overlapping images is to draw each image on its own canvas as well as on the main canvas.
We can then go through the main canvas pixel by pixel clearing any pixel which is in both images, even if it has only very slight opacity.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "rgba(255,0,0,0.5)";
ctx.fillRect(150, 20, 75, 50);
ctx.fillStyle = "rgba(40,23,0,0.5)";
ctx.globalCompositeOperation = "xor";
ctx.fillRect(180, 50, 75, 50);
var c1 = document.createElement('canvas');
var ctx1 = c1.getContext("2d");
ctx1.fillStyle = "rgba(255,0,0,0.5)";
ctx1.fillRect(150, 20, 75, 50);
var c2 = document.createElement('canvas');
var ctx2 = c2.getContext("2d");
ctx2.fillStyle = "rgba(40,23,0,0.5)";
ctx2.fillRect(180, 50, 75, 50);
let imgData = ctx.getImageData(0, 0, 300, 150);
for (let i=0; i < 300; i++) {
for (let j = 0; j < 150; j++) {
//clear the pixel if both images have opacity>0 there
if (ctx1.getImageData(i, j, 1, 1).data[3] && ctx2.getImageData(i, j, 1, 1).data[3] ) {
ctx.clearRect(i, j, 1, 1);
}
}
}
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>

Sequencing of stroke/fill to create a blended overlap

I have a large array of objects to draw on a canvas.
The center of the objects needs to blend with standard alpha.
The border (stroke) of later objects needs to appear to remove any underlying borders while leaving the fill intact for blending.
An example as a code snippet with a couple of failed attempts - please note the 'desired' outcome was produced manually.
The solution needs to scale too as this is for a requestAnimationFrame and there will be thousands of objects to iterated over so performing individual beginPath()/stroke() combinations isn't likely to be viable.
var canvas = document.getElementById('canvas');
canvas.width = 600;
canvas.height = 600;
var ctx = canvas.getContext('2d');
//set up control objects
let objects = [{
x: 20,
y: 20,
w: 60,
h: 30,
rgba: "rgba(255, 0,0,.5)"
}, {
x: 40,
y: 30,
w: 60,
h: 30,
rgba: "rgba(0,255,0,.5)"
}]
//manually produce desired outcome
ctx.beginPath();
for (let i = 0, l = objects.length; i < l; i++) {
let myObject = objects[i];
ctx.fillStyle = myObject.rgba;
ctx.fillRect(myObject.x, myObject.y, myObject.w, myObject.h);
}
ctx.beginPath();
ctx.moveTo(40, 50);
ctx.lineTo(20, 50);
ctx.lineTo(20, 20);
ctx.lineTo(80, 20);
ctx.lineTo(80, 30);
ctx.rect(40, 30, 60, 30);
ctx.stroke();
ctx.font = "15px Arial"
ctx.fillStyle = "black";
ctx.fillText("Desired outcome - (done manually for example)", 120, 50);
//Attempt one: fill on iterate, stroke on end
ctx.beginPath();
for (let i = 0, l = objects.length; i < l; i++) {
let myObject = objects[i];
ctx.rect(myObject.x, myObject.y + 70, myObject.w, myObject.h);
ctx.fillStyle = myObject.rgba;
ctx.fillRect(myObject.x, myObject.y + 70, myObject.w, myObject.h);
}
ctx.stroke();
ctx.fillStyle = "black";
ctx.fillText("Attempt #1: inner corner of red box fully visible", 120, 120);
//Attempt two: fill and stroke on iterate
for (let i = 0, l = objects.length; i < l; i++) {
let myObject = objects[i];
ctx.beginPath();
ctx.rect(myObject.x, myObject.y + 140, myObject.w, myObject.h);
ctx.fillStyle = myObject.rgba;
ctx.fillRect(myObject.x, myObject.y + 140, myObject.w, myObject.h);
ctx.stroke();
}
ctx.fillStyle = "black";
ctx.fillText("Attempt #2: inner corner of red box partly visible", 120, 170);
ctx.fillText("(This also scales very badly into thousands of strokes)", 120, 190);
<canvas name="canvas" id="canvas" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
You can achieve this by drawing in two passes:
First you will composite your strokes, by iteratively
clearing each previous strokes where the filling would fall, using globalCompositeOperation = "destination-out"
draw this rect's stroke
When this is done, your canvas will only have the final strokes remaining.
Now you have to draw the fills, but since we want the strokes to be in front of the fills, we have to use an other compositing mode: "destination-over" and to iterate our rects in reversed order:
(async () => {
var canvas = document.getElementById('canvas');
canvas.width = 600;
canvas.height = 600;
var ctx = canvas.getContext('2d');
ctx.scale(2,2)
//set up control objects
let objects = [{
x: 20,
y: 20,
w: 60,
h: 30,
rgba: "rgba(255, 0,0,.5)"
}, {
x: 40,
y: 30,
w: 60,
h: 30,
rgba: "rgba(0,255,0,.5)"
},
{
x: 10,
y: 5,
w: 60,
h: 30,
rgba: "rgba(0,0,255,.5)"
}]
// first pass, composite the strokes
for (let i = 0, l = objects.length; i < l; i++) {
let myObject = objects[i];
ctx.beginPath();
ctx.rect(myObject.x, myObject.y, myObject.w, myObject.h);
// erase the previous strokes where our fill will be
ctx.globalCompositeOperation = "destination-out";
ctx.fillStyle = "#000"; // must be opaque
ctx.fill();
// draw our stroke
ctx.globalCompositeOperation = "source-over";
ctx.stroke();
}
await wait(1000);
// second pass, draw the colored fills
// we will draw from behind to keep the stroke at frontmost
// so we need to iterate our objects in reverse order
for (let i = objects.length- 1; i >= 0; i--) {
let myObject = objects[i];
// draw behind
ctx.globalCompositeOperation = "destination-over";
ctx.fillStyle = myObject.rgba;
ctx.fillRect(myObject.x, myObject.y, myObject.w, myObject.h);
}
})();
function wait(ms){
return new Promise(res => setTimeout(res, ms));
}
<canvas name="canvas" id="canvas" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
And of course, this can be used in an animation too:
var canvas = document.getElementById('canvas');
canvas.width = 100;
canvas.height = 100;
var ctx = canvas.getContext('2d');
//set up control objects
let objects = [{
x: 20,
y: 20,
w: 60,
h: 30,
rgba: "rgba(255, 0,0,.5)"
}, {
x: 40,
y: 30,
w: 60,
h: 30,
rgba: "rgba(0,255,0,.5)"
},
{
x: 10,
y: 5,
w: 60,
h: 30,
rgba: "rgba(0,0,255,.5)"
}]
objects.forEach( rect => {
rect.speedX = Math.random() * 2 - 1;
rect.speedY = Math.random() * 2 - 1;
});
requestAnimationFrame(anim);
onclick = anim
function anim() {
update();
draw();
requestAnimationFrame( anim );
}
function update() {
objects.forEach( rect => {
rect.x = rect.x + rect.speedX;
rect.y = rect.y + rect.speedY;
if(
rect.x + rect.w > canvas.width ||
rect.x < 0
) {
rect.speedX *= -1;
}
if(
rect.y + rect.h > canvas.height ||
rect.y < 0
) {
rect.speedY *= -1;
}
});
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// first pass, composite the strokes
for (let i = 0, l = objects.length; i < l; i++) {
let myObject = objects[i];
ctx.beginPath();
ctx.rect(myObject.x, myObject.y, myObject.w, myObject.h);
// erase the previous strokes where our fill will be
ctx.globalCompositeOperation = "destination-out";
ctx.fillStyle = "#000"; // must be opaque
ctx.fill();
// draw our stroke
ctx.globalCompositeOperation = "source-over";
ctx.stroke();
}
// second pass, draw the colored fills
// we will draw from behind to keep the stroke at frontmost
// so we need to iterate our objects in reverse order
for (let i = objects.length- 1; i >= 0; i--) {
let myObject = objects[i];
// draw behind
ctx.globalCompositeOperation = "destination-over";
ctx.fillStyle = myObject.rgba;
ctx.fillRect(myObject.x, myObject.y, myObject.w, myObject.h);
}
ctx.globalCompositeOperation = "source-over";
}
<canvas name="canvas" id="canvas" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>

How do I move an element on a canvas around with an animation?

I have been looking for a while on how to move a certain square around on a canvas with JavaScript, and haven't found much. I have done one where it removes itself and replaces itself every frame, but I want it to be smoother and animated. This is my code:
<canvas id="myCanvas" width="200" height="100" style="border:1px solid grey;"></canvas><br />
<button onclick="#">Move Up</button>
<script>
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(20, 60, 20, 20);
</script>
So far the button does nothing, is there a function I could add that would move the square around? (in this case up)
To make smooth animations, check about the requestAnimationFrame function (https://developer.mozilla.org/fr/docs/Web/API/Window/requestAnimationFrame).
Here an example with your code:
canvas = document.getElementById('myCanvas');
ctx = canvas.getContext('2d');
var squareY = 60;
var isButtonPressed = false;
ctx.fillStyle = '#FF0000';
ctx.fillRect(20, squareY, 20, 20);
function moveUp() {
window.requestAnimationFrame(moveUp);
if (isButtonPressed) {
squareY -= 10 / 16;
}
squareY = Math.max(squareY, 5);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#FF0000';
ctx.fillRect(20, squareY, 20, 20);
}
function onMouseUp() {
isButtonPressed = false;
}
function onMouseDown() {
isButtonPressed = true;
}
canvas = document.getElementById('myCanvas');
ctx = canvas.getContext('2d');
var squareY = 60;
var isButtonPressed = false;
ctx.fillStyle = '#FF0000';
ctx.fillRect(20, squareY, 20, 20);
function moveUp() {
window.requestAnimationFrame(moveUp);
if (isButtonPressed) {
squareY -= 10 / 16;
}
squareY = Math.max(squareY, 5);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#FF0000';
ctx.fillRect(20, squareY, 20, 20);
}
function onMouseUp() {
isButtonPressed = false;
}
function onMouseDown() {
isButtonPressed = true;
}
window.addEventListener('keydown', function (e) {
if (e.key == 'ArrowUp') {
// if the arrow key is pressed
squareY -= 10 / 16;
}
});
moveUp();
<canvas id="myCanvas" width="200" height="100" style="border:1px solid grey;"></canvas><br />
<button onmousedown="onMouseDown()" onmouseup="onMouseUp()">Move Up</button>
<script>
</script>

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.

Categories

Resources