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();
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 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();
In the code below, the second fillStyle overrides the color specified in first one if I use rect() and then fill() in both places (ie, both rects are green) but works as expected (ie, the first rect being blue and second being green) if I change the first rect() to fillRect(). Why is it so? I thought fillRect() was just rect() and then fill(), right?
ctx.translate(canvas.width/2, canvas.height/2);
ctx.fillStyle = "#5A9BDC";
ctx.fillRect(0, 0, rectWidth, rectHeight);
// ctx.rect(0, 0, rectWidth, rectHeight);
// ctx.fill();
ctx.translate(-canvas.width/2, -canvas.height/2);
ctx.fillStyle = "#31B131";
ctx.rect(0, 0, rectWidth, rectHeight);
ctx.fill();
Tested in Chrome | Fiddle
fillRect
.fillRect is a "stand-alone" command that draws and fills a rectangle.
So if you issue multiple .fillRect commands with multiple .fillStyle commands, each new rect will be filled with the preceeding fillstyle.
ctx.fillStyle="red";
ctx.fillRect(10,10,10,10); // filled with red
ctx.fillStyle="green";
ctx.fillRect(20,20,10,10); // filled with green
ctx.fillStyle="blue";
ctx.fillRect(30,30,10,10); // filled with blue
rect
.rect is part of the canvas's path commands.
Path commands are groups of drawings beginning with the beginPath() and continuing until another beginPath() is issued.
Within each group, only the last styling command wins.
So if you issue multiple .rect commands and multiple .fillStyle commands inside a path, only the last .fillStyle will be used on all the .rect's.
ctx.beginPath(); // path commands must begin with beginPath
ctx.fillStyle="red";
ctx.rect(10,10,10,10); // blue
ctx.fillStyle="green";
ctx.rect(20,20,10,10); // blue
ctx.fillStyle="blue"; // this is the last fillStyle, so it "wins"
ctx.rect(30,30,10,10); // blue
// only 1 fillStyle is allowed per beginPath, so the last blue style fills all
ctx.fill()
As I know there are 3 "rect" functions for canvas: fillRect, strokeRect and rect.
ctx.rect(0,0,rectWidth,rectHeight); // create some shape, there is nothing on the canvas yet
ctx.stroke(); // draw stroke of the shape
ctx.fill(); // fill the shape
There are two shortcuts:
ctx.strokeRect(0,0,rectWidth,rectHeight); // shortcut to stroke rectangle
ctx.fillRect(0, 0, rectWidth, rectHeight); // shortcut to fill rectangle
So, your fill invocation could fill only your shape created with rect.
If you want different colors for different path commands, calling beginPath() before each command works.
ctx.beginPath();
ctx.fillStyle="red";
ctx.rect(10,10,10,10);
ctx.fill()
ctx.beginPath()
ctx.fillStyle="green";
ctx.rect(20,20,10,10);
ctx.fill()
ctx.beginPath()
ctx.fillStyle="blue";
ctx.rect(30,30,10,10);
ctx.fill()
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)