Right now I am playing around with Canvas and its features, however I am experiencing a weird problem. I am currently trying to draw a circle inside of a Triangle made of several "lineTo's". My problem being when I just implement an arc; it draws the Circle but with a line from the center and out towards the right side (angle 0). If I enclose my arc in beginPath and closePath it draws it perfectly however the Triangle disappears (JSFiddle is provided). Why is this happening also am I doing something specifically wrong? I am new to Canvas and I want to learn, thank you in advance!
JSFIDDLE https://jsfiddle.net/720hg2aq/1/
// Draw Triangle
ctx.moveTo((width*0.4), (height*0.05));
ctx.lineTo((width*0.6), (height*0.05));
ctx.moveTo((width*0.6), (height*0.05));
ctx.lineTo((width*0.5), (height*0.15));
ctx.moveTo((width*0.5), (height*0.15));
ctx.lineTo((width*0.4), (height*0.05));
ctx.moveTo((width*0.5), (height*0.09));
// End of Triangle
// Begin Circle
ctx.beginPath();
ctx.arc((width*0.5), (height*0.09), 20, 0 , 2 * Math.PI);
ctx.closePath();
// End Circle
// Draw it out
ctx.strokeStyle = '#000';
ctx.stroke();
The beginPath() method begins a path, or resets the current path.
Once you begin a path, use moveTo(), lineTo(), quadricCurveTo(), bezierCurveTo(), arcTo(), or arc() to make the path, then storke() it.
So the code should be:
ctx.strokeStyle = "black";
// Draw Triangle
ctx.beginPath(); /// Let's start the work!
ctx.moveTo((width*0.4), (height*0.05));
ctx.lineTo((width*0.6), (height*0.05));
ctx.moveTo((width*0.6), (height*0.05));
ctx.lineTo((width*0.5), (height*0.15));
ctx.moveTo((width*0.5), (height*0.15));
ctx.lineTo((width*0.4), (height*0.05));
ctx.moveTo((width*0.5), (height*0.09));
ctx.stroke(); /// Brushing with your dye!!
// End of Triangle
// Begin Circle
ctx.beginPath(); /// Let's start the **NEW** work!
/// Don't let the previous path be connected with the current path!
ctx.arc((width*0.5), (height*0.09), 20, 0 , 2 * Math.PI);
ctx.closePath();
ctx.stroke(); /// Brushing with your dye!!
// End Circle
Related
How do I create a transparent gradient stroke that using html5 canvas? I need it to go from one point to another and look like the below image.
At the moment I have got this:
const gradient = ctx.createLinearGradient(1, 0, 100, 0);
gradient.addColorStop(0, '#fff');
gradient.addColorStop(1, '#d29baf');
ctx.lineWidth = 30;
ctx.strokeStyle = gradient;
ctx.beginPath();
ctx.moveTo(fromXPos, fromYPos);
ctx.lineTo(toXPos, toYPos);
ctx.stroke();
This makes it look like a solid block though like:
Thanks.
Fill a shape
Use a shape and fill it with the gradient.
You can use CSS colour type rgba(red,green,blue,alpha) where red,green,blue are values from 0-255 and alpha is 0 transparent to 1 opaque.
To create a shape you start with ctx.beginPath() to create a new shape then use lineTo(x,y) to mark out each corner. If you want to add another shape using the same fill or stroke you use ctx.moveTo(x,y) to move to the first point.
Note many people use ctx.beginPath(); ctx.moveTo(x,y); but that works just the same as ctx.beginPath(); ctx.lineTo(x,y); As the first point after beginPath is always converted to a moveTo for any type of path object.
const ctx = canvas.getContext("2d");
// draw first box (left of canvas)
ctx.fillStyle = "#ab7383";
ctx.fillRect(20,100,50,50);
// draw second box (to right of first)
ctx.fillStyle = "#904860";
ctx.fillRect(100,20,50,130);
// gradient from top of second box to bottom of both boxes
const g = ctx.createLinearGradient(0, 20, 0, 150);
g.addColorStop(0, `rgba(${0xd2},${0xba},${0xaf},1`); // opaque
g.addColorStop(1, `rgba(${0xd2},${0xba},${0xaf},0`); // transparent
ctx.fillStyle = g;
ctx.beginPath();
ctx.lineTo(70, 100); // top right of first box
ctx.lineTo(100, 20); // top left of second box
ctx.lineTo(100, 150); // bottom left of second box
ctx.lineTo(70, 150); // bottom right of first box
ctx.fill(); // fill the shape
<canvas id="canvas" style="border:2px solid black"></canvas>
I'm finishing a project, but I have one more step to finish.
I want to visualize microphone input by a canvas.
Getting the data from the microphone isn't a problem.
But I want to visualize it in a special way. (see image)
I want to animate each element from the wave.
My problem isn't the animation.
My problem is to create those shapes in the CANVAS.
This is an example of one shape:
I can create a rounded corner shape with the canvas
const draw = () => {
fillRoundedRect(20, 20, 100, 100, 20);
ctx.fillStyle = "red";
ctx.fill();
};
const fillRoundedRect = (x, y, w, h, r) => {
ctx.beginPath();
ctx.moveTo(x+r, y);
ctx.lineTo(x+w-r, y);
ctx.quadraticCurveTo(x+w, y, x+w, y+r);
ctx.lineTo(x+w, y+h-r);
ctx.quadraticCurveTo(x+w, y+h, x+w-r, y+h);
ctx.lineTo(x+r, y+h);
ctx.quadraticCurveTo(x, y+h, x, y+h-r);
ctx.lineTo(x, y+r);
ctx.quadraticCurveTo(x, y, x+r, y);
ctx.fill();
};
Can someone help me with creating a shape like in the second image?
Thanks in advance guys!
Instead of trying to make a single shape with dependency on surrounding shapes and a high risk of headache math-wise, use instead two shapes which you merge using composition. My suggestion anyways.
Draw all the bars in full height using composition mode source-over (default)
Define a single shape on top using some sort of spline (I would suggest a cardinal spline).
Set composition mode to destination-out and render an enclosed shape using the spline as top "line".
Example
This should work in a loop (remember to clear canvas for each frame) but shows only the building stones needed here -
var ctx = c.getContext("2d");
var points = [];
var skippy = 0;
// render all bars
ctx.globalCompositeOperation = "source-over"; // not needed here, but in a loop yes!
// produce bars
ctx.beginPath(); // not needed here, but in a loop yes!
for(var x = 0; x < c.width; x += 30) {
ctx.rect(x, 0, 16, c.height)
// OKIDOKI, lets produce the spline using random points (y) as well
// but not for all, only every second for prettyness... modify to taste
if (skippy++ % 2 === 0) points.push(x, c.height * Math.random());
}
points.push(c.width, c.height * Math.random()); // one last
ctx.fillStyle = "rgb(198, 198, 198)";
ctx.fill();
// render spline
ctx.beginPath();
ctx.moveTo(0, c.height); // bottom left corner
curve(ctx, points); // spline
ctx.lineTo(c.width, c.height); // bottom right corner
ctx.closePath();
ctx.globalCompositeOperation = "destination-out";
ctx.fill();
I am trying to plot a line string on a globe created using D3, but somehow it shows up wrong.
Demo
Here is how the projection and path are set up
var projection = d3.geo.orthographic()
.translate([width / 2, height / 2])
.scale(scale)
.clipAngle(90);
var path = d3.geo.path()
.projection(projection)
.context(context);
Then I just draw it onto the canvas (using the path function)
// the route
context.fillStyle = '#000';
context.strokeStyle = '#000';
context.beginPath();
path(route);
context.fill();
The route variable is a GeoJSONn line string, I can plot the route on the leaflet map and everything works as expected, however when I try to draw it on the globe, it just shows up wrong.
I think it has something to do with projections, but I don't what causes this. Does anyone have any idea how can I correct it?
Instead of filling your path drawn on the canvas, you need to just stroke it:
// the route
context.fillStyle = '#000';
context.strokeStyle = '#000';
context.beginPath();
path(route);
context.stroke(); // Just stroke the path
//context.fill(); // You don't want to fill the path
This will only draw the line as expected. Have a look at this working Plunk.
Alternatively, if you need to specify fill, just set it to the background color (here that is #ccc)
// the route
context.fillStyle = '#ccc';
context.strokeStyle = '#000';
context.beginPath();
path(route);
context.fill();
context.stroke();
I want to draw a dounut path using canvas. It contains the inner and outer arch connecting with line. But I am getting wrongly canvas image. Please see the below image.
Expected:
This is my code.
this.ctx.beginPath();
this.ctx.moveTo(options.x, options.y);
this.ctx.arc(options.x, options.y, options.radius, options.start, options.end, false);
this.ctx.lineTo(options.x, options.y);
this.ctx.arc(options.x, options.y, options.innerR, options.start, options.end, false);
this.ctx.closePath();
Anyone please help me to solve this issue.
Thanks,
Bharathi.
When moving your "pen" to (options.x, options.y) and then drawing a circle around this point, your "pen" first has to go to the starting position of your arc. Here the line is drawn that you don't want to have on your canvas.
To solve this problem, you have to calculate the starting position of your outer circle (depending on the start angle). You should try with sin or cos to calculate your "new" x and y.
It would then look something like
var newX = options.x + options.radius * cos(options.start);
var newY = options.y + options.radius * sin(options.start);
Then move to this position
this.ctx.moveTo(newX, newY);
And draw the circle around the old x and y
this.ctx.arc(options.x, options.y, options.radius, options.start, options.end, false);
For the inner circle and the end positions you can calculate it similar to this.
I have done it using css
var gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
gradient.addColorStop(0, "#008B8B");
gradient.addColorStop(0.75, "#F5DEB3");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
Just remove the last two lines from my above code you will see that the inner circle appears again
SEE DEMO HERE
i have four divs that is p1,p2,p3,p4. it is draggable. at any point i click "draw" button iwant to draw angle sign like below
$(document).ready(function(){
var c=document.getElementById('canvas');
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.moveTo(parseInt($("#p1").css("left"))-5,parseInt($("#p1").css("top"))-5)
ctx.lineTo(parseInt($("#p2").css("left"))-5,parseInt($("#p2").css("top"))-5)
ctx.lineTo(parseInt($("#p3").css("left"))-5,parseInt($("#p3").css("top"))-5)
ctx.lineTo(parseInt($("#p4").css("left"))-5,parseInt($("#p4").css("top"))-5)
ctx.lineTo(parseInt($("#p1").css("left"))-5,parseInt($("#p1").css("top"))-5)
ctx.fillStyle='#E6E0EC';
ctx.fill();
ctx.strokeStyle="#604A7B";
ctx.lineWidth="3"
ctx.stroke();
ctx.closePath();
$("#p1,#p2,#p3,#p4").draggable({
drag:function(){
ctx.clearRect(0,0,500,500);
ctx.beginPath();
ctx.moveTo(parseInt($("#p1").css("left"))-5,parseInt($("#p1").css("top"))-5)
ctx.lineTo(parseInt($("#p2").css("left"))-5,parseInt($("#p2").css("top"))-5)
ctx.lineTo(parseInt($("#p3").css("left"))-5,parseInt($("#p3").css("top"))-5)
ctx.lineTo(parseInt($("#p4").css("left"))-5,parseInt($("#p4").css("top"))-5)
ctx.lineTo(parseInt($("#p1").css("left"))-5,parseInt($("#p1").css("top"))-5)
ctx.fillStyle='#E6E0EC';
ctx.fill();
ctx.strokeStyle="#604A7B";
ctx.lineWidth="3"
ctx.stroke();
ctx.closePath();
}
});
How can i make this please provide simple solution.
the fiddle:http://jsfiddle.net/b954W/
i want to draw the arc inside the shape at any point.
Here's how to illustrate the angle between line segments
Demo: http://jsfiddle.net/m1erickson/XnL3B/
Step#1: Calculate the angles
You can calculate the angle between 2 lines connected at a vertex using Math.atan2:
// calculate the angles in radians using Math.atan2
var dx1=pt1.x-pt2.x;
var dy1=pt1.y-pt2.y;
var dx2=pt3.x-pt2.x;
var dy2=pt3.y-pt2.y;
var a1=Math.atan2(dy1,dx1);
var a2=Math.atan2(dy2,dx2);
Step#2: Draw the angle's wedge
You can draw the wedge illustrating the angle using context.arc:
// draw angleSymbol using context.arc
ctx.save();
ctx.beginPath();
ctx.moveTo(pt2.x,pt2.y);
ctx.arc(pt2.x,pt2.y,20,a1,a2);
ctx.closePath();
ctx.fillStyle="red";
ctx.globalAlpha=0.25;
ctx.fill();
ctx.restore();
Step#3: Draw the degree angle in text
And you can draw the text of the angle (converted to degrees) using context.fillText:
// draw the degree angle in text
var a=parseInt((a2-a1)*180/Math.PI+360)%360;
ctx.fillStyle="black";
ctx.fillText(a,pt2.x+15,pt2.y);