How to remove intersection of two transparent shapes on canvas? - javascript

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>

Related

Edit lineTo points (in canvas)

I want to move lineTo points.
How to do it?
I'm new to Canvas.
I'll give an example with Path.
This is my example:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(20, 20);
var line = ctx.lineTo(300, 100);
ctx.lineTo(70, 100);
ctx.lineTo(20, 20);
ctx.fillStyle = "red";
ctx.fill();
setTimeout(function() {
/*
I want something like this:
line.editpoints(300, 150);
*/
}, 3000);
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;"></canvas>
Well, canvas as the name suggests, is a canvas (just like in paintings). You can draw on it, but you cannot move things on it as it is not "dynamic".
What you can do, though, is clear it and then draw on top at a different location.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
function clearContext(ctx) {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}
function drawTriangle(offsetX = 0, offsetY = 0) {
ctx.beginPath();
ctx.moveTo(offsetX + 20, offsetY + 20);
var line = ctx.lineTo(offsetX + 300, offsetY + 100);
ctx.lineTo(offsetX + 70, offsetY + 100);
ctx.lineTo(offsetX + 20, offsetY + 20);
ctx.fillStyle = "red";
ctx.fill();
}
drawTriangle();
setTimeout(function() {
clearContext(ctx);
drawTriangle(50, 50);
}, 3000);
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #d3d3d3;"></canvas>

Fade in items individually on a canvas

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>

How can I get the "outline" of a Path stroke, and get the points to create a filled Path shape?

I want to retrieve the corresponding points to a 'outlinestroke' and save it as a Shape, instead of a "path with a stroke"
<!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.beginPath();
ctx.moveTo(20, 20);
ctx.lineWidth = 12;
ctx.lineCap = 'round'
ctx.quadraticCurveTo(20, 100, 200, 20);
ctx.stroke();
</script>
</body>
</html>
This is the result of the code:
But I want to have the Outline of this stroke, and turn it into a Path and give it a stroke.
The fill should be transparent.
And only have a small outline.
Is there a way to "trace or convert" the stroke to a outline path to get the following result:
And if this is not possible:
Before drawing, to use the given points to define the shape of a path.
Here is what I tried:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var width = 12;
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.lineWidth = width;
ctx.quadraticCurveTo(20, 100, 200, 20);
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = 1;
ctx.fillStyle = "#ccc";
ctx.moveTo(20-width/2, 270);
ctx.quadraticCurveTo(20-width/2, 350+width/2, 200-width/2, 270+width/2);
ctx.lineTo(200-width/2, 270-width/2);
ctx.quadraticCurveTo(20+width/2, 350-width/2, 20+width/2, 270-width/2);
ctx.lineTo(20-width/2, 270);
ctx.fillStyle = "#999";
ctx.fill();
ctx.stroke();
ctx.closePath();
Which results in the following:
There are no API features to turn a strokes outline into a path.
You can however use a composite operation to create the inner transparency.
Example
Creating outline using globalCompositeOperation = "destination-out";
The gradient is just to show it is transparent.
const OUTLINE_WIDTH = 1; // in pixels
var ctx = canvas.getContext("2d");
ctx.lineWidth = 22;
ctx.lineCap = 'round'
ctx.beginPath();
ctx.moveTo(20, 20);
ctx.quadraticCurveTo(20, 100, 200, 20);
ctx.stroke();
ctx.globalCompositeOperation = "destination-out";
ctx.lineWidth = 22 - OUTLINE_WIDTH * 2;
ctx.stroke();
ctx.globalCompositeOperation = "source-over"; // restore default
canvas {
border:1px solid #aaa;
background: linear-gradient(90deg, rgba(180,255,224,1) 0%, rgba(169,169,255,1) 100%);
}
<canvas id="canvas"></canvas>

How do I clear ONLY rectangle borders? (JS , Canvas)

I'm trying to clear only the strokeRect() and keep content in that rectangle.
In this example, how do I clear green rectangle without affecting the red one?
var cut = [50, 70, 100, 100]
var cut1 = [60, 85, 60, 60]
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.rect(cut[0], cut[1], cut[2], cut[3]);
ctx.lineWidth = 3;
ctx.strokeStyle = 'green';
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.rect(cut1[0], cut1[1], cut1[2], cut1[3]);
ctx.lineWidth = 3;
ctx.strokeStyle = 'red';
ctx.stroke();
ctx.closePath();
<canvas id="canvas" width=400px height=200px></canvas>
Can't figure out how..
Thanks in advance!
You need to clear the canvas and draw the red rectangle again.
var c = document.getElementById("canvas");
c.width=400;
c.height=200;
var ctx = c.getContext("2d");
var cut = [50, 70, 100, 100]
var cut1 = [60, 85, 60, 60]
function drawRectangle(cut,fill){
ctx.beginPath();
ctx.rect(cut[0], cut[1], cut[2], cut[3]);
ctx.lineWidth = 3;
ctx.strokeStyle = fill;
ctx.stroke();
ctx.closePath();
}
drawRectangle(cut,"green");
drawRectangle(cut1,"red");
clear.addEventListener("click",()=>{
ctx.clearRect(0,0, c.width, c.height);
drawRectangle(cut1,"red");
});
canvas{display:block;}
<button id="clear">clear</button>
<canvas id="canvas" width=400px height=200px></canvas>
In your case, clear & redraw is what you really need, but just for completeness, to clear in any shape, you can use compositing operations.
By setting the compositing mode to destination-out, all the pixels that should normally have been filled by your drawings will actually get rendered as transparent.
So to make a simple clear-stroke-rect:
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'red';
ctx.fillRect(20, 20, 80, 80);
// clear
ctx.globalCompositeOperation = 'destination-out';
ctx.lineWidth = 5;
ctx.strokeRect(40,40,30,30);
// set back to 'normal'
ctx.globalCompositeOperation = 'source-over';
<canvas id="canvas"></canvas>
But using compositing, you can really clear in any shape, even from bitmap with transparency:
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
ctx.fillStyle = 'red';
ctx.fillRect(20, 20, 80, 80);
// clear
ctx.globalCompositeOperation = 'destination-out';
ctx.drawImage(img, 40,40);
// set back to 'normal'
ctx.globalCompositeOperation = 'source-over';
};
img.src = 'https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png';
<canvas id="canvas"></canvas>

Adding Image within a canvas circle

I am learning drawing canvas and now I have task. I need to add an image within the inner circle. The image position needs to be inside the circle. Also I attached the image with this post. My code are:
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #c3c3c3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(0,0,200,100);
var cicleT = document.getElementById("myCanvas");
var dtx = cicleT.getContext("2d");
dtx.arc(95,50,40,0,2*Math.PI);
dtx.stroke();
dtx.fillStyle = "red";
dtx.fill();
dtx.fillStyle = "black"; // font color to write the text with
var font = "bold 13px serif";
dtx.font = font;
dtx.textBaseline = "bottom";
dtx.fillText("Bangladesh",50,50, 95 ,25);
</script>
</body>
</html>
You can use ctx.clip to cut out the region you want to draw, and the following operation will be refined on the region, remember to restore when you complete the works that needs to be refined.
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(0, 0, 200, 100);
ctx.arc(95,50,40,0,2*Math.PI);
ctx.stroke();
ctx.fillStyle = "red";
ctx.fill();
// For safety, I move the draw image and draw text to image.onload.
var image = document.createElement('img');
image.onload = function() {
var iw = image.width;
var ih = image.height;
var r = Math.sqrt(Math.pow(iw/2, 2) + Math.pow(ih/2, 2));
var ratio = 40 / r;
var tw = iw * ratio;
var th = ih * ratio;
// Use the same ctx is ok.
ctx.arc(95, 50, 40, 0, 2 * Math.PI);
ctx.stroke();
// Save the current state of context, which is not clipped yet.
ctx.save();
// Clip by the stroke.
ctx.clip();
// Draw image.
//
ctx.drawImage(image, 0, 0, iw, ih, 95 - tw/2, 50 - th/2, tw, th);
// Restore the context, otherwise the text will also be clipped.
ctx.restore();
ctx.fillStyle = "black"; // font color to write the text with
var font = "bold 13px serif";
ctx.font = font;
ctx.textBaseline = "bottom";
ctx.fillText("Bangladesh", 50, 50, 95, 25);
};
image.src = "https://i.stack.imgur.com/jy3YL.jpg";
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #c3c3c3;">
Your browser does not support the HTML5 canvas tag.
</canvas>

Categories

Resources