I am trying to draw a gear in Canvas but running into issues from the start. I want to have a filled circle with a hallowed out middle. Instead, I am getting what looks to be an outline of a single circle.
Here is my code:
var ctx = document.getElementById("canvas").getContext("2d"),
i = 0;
function drawGear(){
ctx.fillStyle = "#000";
ctx.translate(50,50);
ctx.arc(0,0,20,0,Math.PI*2);
ctx.fill();
ctx.fillStyle = "#FFF";;
ctx.arc(0,0,5,0,Math.PI*2);
ctx.fill();
}
drawGear();
http://jsfiddle.net/te3jn/
I believe that the issue is something related to the globalCompositeOperation, but I tried several of them (source-over, source-atop, destination-over) and none seem to work the way I want.
You should begin a new path when drawing the second circle, like this:
ctx.fill();
ctx.beginPath();
ctx.fillStyle = "#FFF";
// ...
JS Fiddle.
Without this, you'll essentially redraw both circles - the inner and the outer one - with the second fill call (check this fiddle for demonstration)
Related
I'm drawing rectangles on a canvas with Javascript. When the user moves his mouse over one of the rectangles, a text should appear in that rectangle. At only that rectangle (i.e., not the other rectangles).
So I managed to draw the rectangles and created the mouseover event. It works perfectly: as soon as the mouse moves over one of the rectangles the text appears. However, the text appears in ALL rectangles... Any thought about what I'm doing wrong? There seems to be a looping problem, but I can't seem to fix it.
function handleMouseMove(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
for(var i=0;i<entities.length;i++){
var entity=entities[i];
ctx.rect(entity.x, entity.y, width, height);
if(ctx.isPointInPath(mouseX,mouseY)){
ctx.font = "10px Arial";
ctx.fillStyle = "black";
ctx.textAlign = "left";
ctx.fillText("edit", entity.x + 5 , entity.y + 5 );
}
}
}
The isPointInPath method will check if the given coordinates are in any of the shapes formed by the current path. Every rect is added to the same, single path which has already been created during your initialisation code that draws the rectangles.
So the effect is that once your mouse is over any of the drawings, the condition is true in each iteration of your loop.
Solve this by creating a new path in each iteration:
for(var i=0;i<entities.length;i++){
var entity=entities[i];
ctx.beginPath(); // <----
ctx.rect(entity.x, entity.y, width, height);
// ...etc
I am very new to js as a whole, and have decided that a good way to get to know and javascript as a whole would be to follow a tutorial for building a simple block-breaking game.
The game itself runs just fine, however, I would like to find a way to replace the js-drawn circle with an image of a ball, and the blocks with any other rectangular images.
I know (I think) that I need to implement var img = new Image()
in some way, but I'm not entirely sure how to go about doing this without managing to make my circle disappear altogether.
I believe the offending area of my code may be this part:
function drawBall(){
ctx.beginPath();
ctx.arc(x, y, ballSize, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
However, given that I am new, I may have completely missed it , and so I also provide a codepen of the project thus far. Codepen
The code that draws the circle is the following:
ctx.arc(x, y, ballSize, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
So instead of drawing a circle (which is done with the .arc), you can draw an image instead using the .drawImage method. See docs. It would look something like this:
ctx.drawImage(image, x, y);
The image argument is an "image source", which could be just a plain <img> element in your HTML. See examples of how to its done in the docs that I linked.
I want to draw something like a donut, so a circle with a hole in the middle. I tried using ctx.clip(), but I realized it limits the path to inside, and I want it to limit the path to the outside.
Things to note:
this.lineWidth is how thick the "rim" or the outside portion is
ctx.beginPath();
// this should be the hole
ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
ctx.clip();
// this should be the outside part
ctx.arc(this.x,this.y,this.r+this.lineWidth,0,Math.PI*2,false);
ctx.fillStyle = "#00ff00";
ctx.fill();
Instead I'm getting a filled-in circle because it's limiting the path to inside the smaller arc instead of outside it. Is there another method that does the opposite of clip()?
I found this solution http://jsfiddle.net/Hnw6a/:
var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
//ctx.arc(x,y,radius,startAngle,endAngle, anticlockwise);
ctx.beginPath()
ctx.arc(100,100,100,0,Math.PI*2, false); // outer (filled)
ctx.arc(100,100,55,0,Math.PI*2, true); // outer (unfills it)
ctx.fill();
With following canvas node:
<canvas id="canvas1" width="500" height="500"></canvas>
Set the linewidth to the desired width, draw your circle, and use "ctx.stroke();". Note that this doesn't allow you to fill the inner circle with a color.
So I'm creating a simple userscript for me - I want to draw a play button over shaded version of any GIF image on the site to have them only played when I want to.
I have inspired myself here. To make the whole thing nice, I'm drawing a green circle over the animation. This is my intended effect (I really wonder if once can make some shapes in GIMP):
And this is what I currently have:
The Cleese ironic face animation comes from this GIF portal
I made a fiddle of my current GIF pauser userscript.
The critical code for printing the circle:
//Assume these variables
var ctx = canvas context (2d)
var w = canvas width
var h = canvas height
//The code:
ctx.beginPath();
//I'm making sure the circle will always fit - therefore Math.min
ctx.arc(w/2, h/2, Math.min(60, w/2-20, h/2-20), 0, 2 * Math.PI, false);
ctx.fillStyle = 'rgba(0,180,0,0.5)';
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = 'red';
ctx.stroke();
ctx.closePath();
I hope it's clear that the triangle must always fit into the circle (size of which may vary). It must have the vertical line a little bit shorter then the other two, which must be of equal length.
I'm totally not interested in any existing GIF pausing libraries. Keep in mind that the question is about the triangle, not the GIFs.
Like this? http://jsfiddle.net/32ECU/
//Draw a triangle in it
ctx.strokeStyle = 'white';
ctx.beginPath();
ctx.moveTo(w/3, h/3);
ctx.lineTo(w/3, h-h/3);
ctx.lineTo(w-w/4, h/2);
ctx.lineTo(w/3, h/3);
ctx.fillStyle = 'white';
ctx.fill();
I am drawing some arrows in canvas (similar arrows can be viewed in a life cycle). I want to draw border to all these arrows individually just like we add to divs. I tried using stroke style and stroke method but it filled my entire arrow.
I am using fill style and fill to fill color to my arrows.
Is there any way to do it? Is it like fill and stroke methods can never be used together?
You'll have to use beginPath() and closePath() on your canvas's context ("ctx" down here), followed by a fill() to actually fill the element:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.moveTo(170, 80);
ctx.lineTo(300,150);
ctx.lineTo(100,150);
ctx.lineTo(170, 80);
// Etc, Make your movements to draw the arrow, here.
ctx.closePath();
//Line settings and drawing
ctx.lineWidth = 5;
ctx.strokeStyle = 'blue';
ctx.stroke();
//Fill settings and drawing
ctx.fillStyle = '#8ED6FF';
ctx.fill();