I am having a problem with drawing circles on a canvas. When I draw a circle on my canvas it works fine, but if I draw a square afterwards, the color of my circle changes to the same color as the square.
This has been troubling me for a while now. Here is a jsbin project to demonstrate what I am talking about:
https://jsbin.com/bajezudayi/edit?html,js,output
On this canvas you can draw circles and squares (note the check box at the top to switch shapes).
I have tried changing the color variable in the drawCircle to a set value instead of being a function argument but the problem persists.
function drawCircle(x,y,rad,col,ctx){
// This function draws a circle on a canvas
ctx.save();
ctx.translate(x,y);
ctx.beginPath();
ctx.arc(0,0,rad,0,2*Math.PI,false);
ctx.fillStyle='red'; // rather than =col
ctx.fill();
ctx.restore();
}
If I apply an animation loop to my canvas, even weirder effects start to happen because of this issue.
Any ideas why this is happening?
Thank you.
Edit:
Here is the full project I am currently working on:
http://adam-day-com.stackstaging.com/orbital/index.html
Try checking the 'show vector field' box and add some planets. The function to draw the vector field (called in an animation loop) draws a series of thin boxes and it messes up the circle colors.
I added ctx.beginPath() and ctx.closePath() and things seem to working fine. Is this what you wanted? https://jsbin.com/ribiyodoru/edit?html,js,output
Related
I want to draw a line on a picture while having an ellipse following the mouse at the mouse position. I have developed the following code, the ellipse always draw on the picture.
function setup() {
createCanvas(400, 400);
}
function draw() {
//background(220);
line(pmouseX, pmouseY, mouseX, mouseY);
fill(255, 0, 0);
ellipse(mouseX, mouseY, 7, 7);
}
You can see that the ellipse is always draw on the picture. How can I remove the ellipse after it shows once?
I am expecting a line is drawn on the picture while an ellipse is shown at the mouse position. The ellipse should not draw on the image, I only follow the mouse location, however, the line will draw on the picture.
I think I understand now what you want.
If you uncomment the background instruction, you will erase the lines drawn so far. If you comment the background the lines will remain, but also the ellipses.
So, for that you need the instruction cursor() that allows you to use a custom mouse cursor.
So, what I would suggest is: Create an image file that contains an ellipse and the background is transparent.
Specify that you want a cursor from a file, by doing
cursor("myCursorImage.png")
Take a look at the reference of the cursor that I provided in a link to see the different parameters you can pass to cursor()
I am trying to draw an opaque shape on top of a colorful background in p5.js. So I give both the fill color and the stroke color an alpha value. The problem is that the outline of the shape is partly drawn onto the shape. Because of the opaque stroke, this makes it look like there is two outlines with different colors. Here is an example:
function setup() {
createCanvas(60, 60);
}
function draw() {
background(255);
fill(127,127);
stroke(50,127);
strokeWeight(5);
rect(10,10,40,40);
}
What I get is this square which appears to have an inner dark gray and an outer light gray bounding box.
Is there an easy way to prevent this from happening? I know I could draw the shape "twice" (first the fill and then the outline a little bit further out), but
I am trying to draw a rather complicated polygon, so I would have to adjust all the vertex coordinates of the outer shape which would be pretty annoying to work out.
I have already tried the different blendModes, but they didn't seem to be able to solve my problem.
The reason this is happening is because you have a stroke weight of 5, which is drawn from the edge of the shape, in both directions. So some of the stroke is on the inside of the shape, and some of the stroke is on the outside.
I don't know of a way to change this setting. I tried playing with strokeCap and strokeJoin but nothing solved the problem.
One option that occurs to me is drawing a scaled-down version of the shape with a stroke weight of 1. That would look something like this:
let shapeGraphics;
function setup() {
createCanvas(260, 260);
// draw a scaled-down version of the shape
shapeGraphics = createGraphics(8, 8);
shapeGraphics.fill(127, 127);
shapeGraphics.stroke(50, 127);
shapeGraphics.rect(0, 0, 8, 8);
}
function draw() {
background(255);
noSmooth();
// draw a scaled-up version of the graphics
image(shapeGraphics, 10, 10, 40, 40);
}
If that doesn't work, then the only other option I can think of is to calculate the outer edges yourself and draw the shape twice, like you mentioned.
I am working on a real time canvas drawing webapp using socket.io, node.js, and p5.js. I am having trouble creating a smooth line when the mouse is dragged. If the mouse is dragged too fast there is a trail of empty space in between each ellipse. The end goal here is to create a smooth path. Here are the things I have tried so far:
Attempt 1:
noStroke();
fill(lineColor[0],lineColor[1],lineColor[2]);
ellipse(mouseX, mouseY, lineThickness, lineThickness);
Attempt 2:
strokeWeight(lineThickness);
line(mouseX,mouseY);
stroke(lineColor[0],lineColor[1],lineColor[2]);
Here is a picture of what the issue looks like:
canvas drawing incomplete path image
any feedback is welcome; thanks!
Kevin's answer is great because it will be more efficient to draw lines instead of many ellipses. You should also look into:
beginShape()/endShape()
bezierVertex()
curveVertex()
curvePoint()
The above should help you draw a smooth path and setting a thicker stroke will looks as it many filled ellipses are connected forming the path.
If for some reason you do want to draw many ellipses, you can interpolate position when the mouse move faster and create gaps to fill those gaps.
For more information and p5.js example, check out this answer:
Processing: Draw vector instead of pixels
You could use the pmouseX and pmouseY variables, which hold the previous position of the cursor. Use that to draw a line from the previous position to the current position to fill in the blank space between mouse events.
From the reference:
// Move the mouse across the canvas to leave a trail
function setup() {
//slow down the frameRate to make it more visible
frameRate(10);
}
function draw() {
background(244, 248, 252);
line(mouseX, mouseY, pmouseX, pmouseY);
print(pmouseX + " -> " + mouseX);
}
<script src="https://github.com/processing/p5.js/releases/download/0.5.11/p5.js"></script>
I'm trying to understand the combination of HTML5/CSS3 and Javascript more and more.
That's why I thought, make a little project so you learn all about that more.
In short, I like the new iOS7 wallpaper and use it on my website (http://www.betadevelops.com). Then I thought, let's make this more lightweight and draw it with pure Javascript.
I started and managed to get quite far (http://www.betadevelops.com/jOS7.html). But now I face a stupid problem I can't seem to get fixed.
I draw circles on the canvas, and dynamically assign colors to it. But each time a new circle (and so a new color gets chosen) it automatically recolors the old circles...
So let's say, 10 circles:
1: blue circle, draw's it and done
2: yellow circle, draw's it and done, but it also colors the first blue one to yellow
I also wanted to add opacity and blurring. The opacity kinda works in the sense it has opacity on only 2-3 circles from the 20 I draw. I think this is not possible because I use Math.Random the calculate a random opacity.
Considered the blurring, I can add blurring to the whole canvas with follow code
canvas.style.webkitFilter = "blur(3px)";
but that's not what I want. I want the blur on the circle itself and to be more precisely, the outline. I read about it and it's not possible, but you can mimmick the looks with using CSS box-shadow.
So I tried
canvas.style.webkitFilter = "box-shadow(10px 10px 5px #888)";
but this also doesn't work it seems...
So, you website guru's. What am I doing wrong and can you help me out?
You can find the code by clicking on the second link. Uploaded it there.
EDIT:
Nevermind the blur, managed to solve it partially with this code
if (blurred) {
ctx.shadowColor = color;
ctx.shadowBlur = 15;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
}
#Stig Runar Vangen has the correct answer.
I would just add that if you don't intend the circles to "run", you could use ctx.closePath after drawing each ctx.arc.
ctx.beginPath();
ctx.arc(centerX, centerY, diameter, 0, 2 * Math.PI, false);
ctx.closePath();
color = color.replace('opacity', Math.random().toString());
ctx.fillStyle = color;
ctx.fill();
The reason why you see that all your circles gets the same color, might be because you join all circles into one draw operation. To separate each circle draw operation, start each circle placement with:
ctx.beginPath();
Each arc should then also be drawn with a call to either ctx.stoke() or ctx.fill() after the definition of each single circle.
This is purely guesswork as I haven't seen your code.
I am using an HTML canvas and javascript and I need to clear all of the pixels underneath a shape created by closing a path (for example, I am using flot, and I want to make rounded corners, and to do this, I first need to remove the square corners by drawing a curve on top of the corner to remove the desired pixels).
Right now, I am doing this by just filling the shape with the same color as the background, which can imitate what I want to do, but, it is not ideal as it makes it impossible to place the chart on top of non-solid backgrounds without seeing the square corners. I know that there is a clearRect method that would do what I want to do, but with only rectangles, I need to do it with any closed shape. Is it possible, and if so, how would I do it?
brainjam's code was heading in the right direction, but didn't fully solve the problem. Here's the solution:
context.save();
context.globalCompositeOperation = 'copy';
context.fillStyle = 'rgba(0,0,0,0)';
//draw shape to cover up stuff underneath
context.fill();
context.restore();
Here's an example of a function that will clear a circle from a canvas:
var clearCircle = function(x, y, radius)
{
context.save();
context.globalCompositeOperation = 'destination-out';
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fill();
context.restore();
};
I think what you want is a clipping region, defined by the clip() function. The latter takes a bunch of paths. Here's an example.
This is a little different from what you are specifically asking (which is to remove pixels after drawing them), but actually not drawing the pixels in the first place is probably better, if I understand your requirements correctly.
Edit: I now think I understand that what you want to do is clear pixels to transparent black. To do that, after having defined your paths, do something like this:
context.fillStyle = 'rgba(0,0,0,0)';
context.fill();
The first statement sets the fill color to transparent black.
Use globalCompositeOperation = 'destination-out' instead of 'copy', it will erase all pixels of the shape in the canvas.
See all kinds of composition here
very usefull !