How can you fill a shape created in javascript with an image?
I am using a shape I created with javascript and am right now filling it with a color. How can I replace that and fill it with an image/gif of my choice?
function shape(x,y) {
ctx.fillStyle = "#9dd4ff";
ctx.beginPath();
ctx.moveTo(232,213)
ctx.lineTo(315,198);
ctx.lineTo(x,y);
ctx.closePath();
ctx.fill();
}
You can solve this problem by using your path as a MASK
HERE IS THE CODE
// Create an image element
var img = document.createElement('IMG');
// When the image is loaded, draw it
img.onload = function () {
// Save the state, so we can undo the clipping
ctx.save();
// Create a shape, of some sort
ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(100, 30);
ctx.lineTo(180, 10);
ctx.lineTo(200, 60);
ctx.arcTo(180, 70, 120, 0, 10);
ctx.lineTo(200, 180);
ctx.lineTo(100, 150);
ctx.lineTo(70, 180);
ctx.lineTo(20, 130);
ctx.lineTo(50, 70);
ctx.closePath();
// Clip to the current path
ctx.clip();
ctx.drawImage(img, 0, 0);
// Undo the clipping
ctx.restore();
}
// Specify the src to load the image
img.src = "https://www.google.com/images/srpr/logo3w.png";
Try this:
var thumbImg = document.createElement('img');
thumbImg.src = 'path_to_image';
function shape(x,y) {
ctx.fillStyle = "#9dd4ff";
ctx.beginPath();
ctx.moveTo(232,213)
ctx.lineTo(315,198);
ctx.lineTo(x,y);
ctx.drawImage(thumbImg, 0, 0, 50, 50);
ctx.closePath();
ctx.fill();
}
-- Edit --
Remove ctx.fillStyle ="#9dd4ff"
As you need to mention the path of image.
Related
I have an issue where I am grabbing a users displayAvatar() and then I use an arc to make the image round. This works fine, however, I need to place a circle on top of that image, but it is getting cut in half because of the previous clip()
Without clip() : https://i.gyazo.com/b474c656f33a1f004f5e3becffcef527.png
With clip() : https://i.gyazo.com/da13377cd3f6dc7516c2b8fd1f0f8ac9.png
I know that in the 'With clip()' image, it appears as if the arc border is showing outside of the clip, but that is hardcoded into the image, I put it as a guide with an image editor.
I tried moving around the code, I removed the line ctx.clip() and saw that my circle displays fine on top of the image.
// circle around avatar
ctx.beginPath();
ctx.arc(122.5, 141.8, 81, 0, Math.PI * 2, true);
ctx.closePath();
ctx.clip();
const avatar = await Canvas.loadImage(
message.author.displayAvatarURL({ format: 'png' })
);
ctx.strokeStyle = '#ffffff';
ctx.strokeRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(avatar, 41.5, 60.5, 162, 162);
// presence circle
ctx.beginPath();
ctx.arc(184.5, 193.5, 19, 0, Math.PI * 2, true);
ctx.strokeStyle = '#000000';
ctx.lineWidth = 8;
ctx.stroke();
ctx.fillStyle = userStatusColor;
ctx.fill();
Take a look at the canvas clip() definition:
https://www.w3schools.com/tags/canvas_clip.asp
Tip: Once a region is clipped, all future drawing will be limited to the clipped region (no access to other regions on the canvas). You can however save the current canvas region using the save() method before using the clip() method, and restore it (with the restore() method) any time in the future.
Below is an example using the save and restore
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(90, 90, 81, 0, Math.PI * 2, true);
ctx.stroke();
ctx.save();
ctx.clip();
ctx.beginPath();
ctx.arc(150, 50, 19, 0, Math.PI * 2, true);
ctx.fillStyle = '#0000ff';
ctx.lineWidth = 8;
ctx.stroke();
ctx.fill();
ctx.restore();
ctx.beginPath();
ctx.arc(170, 99, 19, 0, Math.PI * 2, true);
ctx.fillStyle = '#ff0000';
ctx.lineWidth = 8;
ctx.stroke();
ctx.fill();
<canvas id="canvas"></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'm wondering if the following code yields appropriate behavior. I feel like the top left square should still be green. that is, if I clip one area, ten restore, then paint in a second area, the canvas paints in BOTH areas. Why?
https://jsfiddle.net/s6t8k3w3/
var my_canvas = document.getElementById('canvas');
var ctx = my_canvas.getContext("2d");
//Make Clipping Path 1
ctx.save();
ctx.rect(20, 20, 100, 100);
ctx.clip();
//Fill Background with Green
ctx.fillStyle = 'rgba(0,255,0,1)';
ctx.fillRect(0, 0, my_canvas.width, my_canvas.height);
//Close Clipping Path 1
ctx.restore();
//Open Clipping Path 2
ctx.save();
ctx.rect(50, 50, 100, 100);
ctx.clip();
//Fill background with Blue
ctx.fillStyle = 'rgba(0,0,255,1)';
ctx.fillRect(0, 0, my_canvas.width, my_canvas.height);
//Draw Line
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(500, 500);
ctx.stroke();
//CloseClipping Path 2
ctx.restore();
You're not actually opening a second clipping path with that second ctx.save(); to do that, you need to call ctx.beginPath()
Canvas shadow properties seem to affect all paths that follow it, even when closing the path that contains those properties. I tried changing the order of things. Ok, placing a path that doesnt require a shadow before the one that does works, but that isnt very reliable work-around. Is there any way to fix this?
Here a simple Jsfiddle demonstrating the problem: http://jsfiddle.net/zrt61283/1/
var c=document.getElementById("canvas");
var ctx=c.getContext("2d");
// Left
ctx.beginPath();
ctx.arc(100, 75, 20, 0, 2 * Math.PI);
ctx.shadowColor = 'blue';
ctx.shadowBlur = 30;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.stroke();
ctx.fill();
ctx.closePath();
// Right
ctx.beginPath();
ctx.arc(200, 75, 20, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
ctx.closePath();
you can reset the shadowBlur property with ctx.shadowBlur = 0; or ctx.shadowBlur = null;
for more info take a look at specs shadowBlur (canvas2dAPI).
here's an alternative way using save() and restore();
fiddle
As others have said doing a reset will work - also you can do .save() which will save the canvas state, you will need to restore as well...
var c=document.getElementById("canvas");
var ctx=c.getContext("2d");
// Left
ctx.save();
ctx.beginPath();
ctx.arc(100, 75, 20, 0, 2 * Math.PI);
ctx.shadowColor = 'blue';
ctx.shadowBlur = 30;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.stroke();
ctx.fill();
ctx.closePath();
ctx.restore();
// Right
ctx.save();
ctx.beginPath();
ctx.arc(200, 75, 20, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill();
ctx.closePath();
ctx.restore();
This will basically save the state of the canvas and allow you to take actions within it, then add new things to the canvas and keep them as different pieces.
here is a quick fiddle of this being used - https://jsfiddle.net/e0qm94dn/
I am read tons of documentation about save/restore canvas states, but still confused with next example.
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
// save default state
ctx.save();
// draw new arc with new settings
ctx.lineWidth = 2;
ctx.fillStyle = '#bfb';
ctx.strokeStyle = '#999';
ctx.beginPath();
ctx.arc(50, 50, 10, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
ctx.stroke();
// restore default state
ctx.restore();
// save default state again
ctx.save();
// draw line with new settings
ctx.lineWidth = 4;
ctx.strokeStyle = '#000';
ctx.moveTo(50, 50);
ctx.lineTo(100, 100);
ctx.stroke();
// restore default state
ctx.restore();
// save default state third time
ctx.save();
// draw round circle with new settings
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle = '#999';
ctx.arc(100, 100, 10, 0, 2 * Math.PI);
ctx.closePath();
ctx.fillStyle = '#bfb';
ctx.fill();
ctx.stroke();
// restore default state
ctx.restore();
}
draw();
My logic in code comments, but result absolutely not expected. First circle has a settings from line. Circles should have different style from line.
I am not good at canvas just yet but with some basic learning I think
You are missing ctx.beginPath(); before starting to draw path.
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
// save default state
ctx.save();
// draw new arc with new settings
ctx.lineWidth = 2;
ctx.fillStyle = '#bfb';
ctx.strokeStyle = '#999';
ctx.beginPath();
ctx.arc(50, 50, 10, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
ctx.stroke();
// restore default state
ctx.restore();
// save default state again
ctx.save();
// draw line with new settings
ctx.beginPath();
ctx.lineWidth = 4;
ctx.strokeStyle = '#000';
ctx.moveTo(50, 50);
ctx.lineTo(100, 100);
ctx.stroke();
// restore default state
ctx.restore();
// save default state third time
ctx.save();
// draw round circle with new settings
ctx.beginPath(); /* ** THIS is missing in your code ** */
ctx.lineWidth = 2;
ctx.strokeStyle = '#999';
ctx.arc(100, 100, 10, 0, 2 * Math.PI);
ctx.closePath();
ctx.fillStyle = '#bfb';
ctx.fill();
ctx.stroke();
// restore default state
ctx.restore();
}
draw();
DEMO
SOURCE