Draw triangle by the intersect of 3 circles - javascript

I want to draw a triangle base on the intersection points of 3 circles. Is there any function or any method with JavaScript to solve this? Or I need to perform some math calculation to get exact position of the intersection point and draw the triangle myself.
function drawMap(){
var ctx = $('#map')[0].getContext("2d");
// Draw the map of my room 400cm * 300cm
ctx.fillStyle = "#ecf0f1"
ctx.beginPath();
ctx.rect(0, 0, 300, 400);
ctx.closePath();
ctx.fill();
//Draw the first circle (blue one)
ctx.fillStyle = "rgba(52, 152, 219,0.5)";
ctx.beginPath();
ctx.arc(0, 0, 200, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
//Draw the second circle(green one)
ctx.fillStyle = "rgba(46, 204, 113,0.5)";
ctx.beginPath();
ctx.arc(0, 400, 250, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
// Draw the third circle (yellow one)
ctx.fillStyle = "rgba(241, 196, 15,0.5)";
ctx.beginPath();
ctx.arc(300, 200, 280, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
}

Finding the intersection points which are on the circumference of all three circles
Here's how to do it:
Define 3 circles:
var A={x:0,y:0,r:200,color:"rgba(52, 152, 219,0.5)"};
var B={x:0,y:400,r:250,color:"rgba(46, 204, 113,0.5)"};
var C={x:300,y:200,r:280,color:"rgba(241, 196, 15,0.5)"};
Calculate the intersection points of the 3 circles vs each other (AB,BC,CA):
var intersections=[];
var AB=circleIntersections(A,B); // see example code below for circleIntersections()
var BC=circleIntersections(B,C);
var CA=circleIntersections(C,A);
if(AB){intersections.push(AB);}
if(BC){intersections.push(BC);}
if(CA){intersections.push(CA);}
Test each intersection point. Keep any intersection points that are in all 3 circles.
var triangle=[];
for(var i=0;i<intersections.length;i++){
var pt=intersections[i];
if(ptIsInCircle(pt,A) && ptIsInCircle(pt,B) && ptIsInCircle(pt,C)){
triangle.push(pt);
}
}
In your example code you are left with 3 intersection points that are also in all 3 circles.
But with circles positioned elsewhere you might get fewer or more than 3 intersection points.
Use context path commands to draw a polyline between the 3 discovered points.
if(triangle.length==3){
ctx.beginPath();
ctx.moveTo(triangle[0].x,triangle[0].y);
ctx.lineTo(triangle[1].x,triangle[1].y);
ctx.lineTo(triangle[2].x,triangle[2].y);
ctx.closePath();
ctx.stroke();
}
Example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
var A={x:0,y:0,r:200,color:"rgba(52, 152, 219,0.5)"};
var B={x:0,y:400,r:250,color:"rgba(46, 204, 113,0.5)"};
var C={x:300,y:200,r:280,color:"rgba(241, 196, 15,0.5)"};
var intersections=[];
var AB=circleIntersections(A,B);
var BC=circleIntersections(B,C);
var CA=circleIntersections(C,A);
if(AB){intersections=intersections.concat(AB);}
if(BC){intersections=intersections.concat(BC);}
if(CA){intersections=intersections.concat(CA);}
var triangle=[];
for(var i=0;i<intersections.length;i++){
var pt=intersections[i];
if(ptIsInCircle(pt,A) && ptIsInCircle(pt,B) && ptIsInCircle(pt,C)){
triangle.push(pt);
}
}
drawMap();
if(triangle.length==3){
ctx.beginPath();
ctx.moveTo(triangle[0].x,triangle[0].y);
ctx.lineTo(triangle[1].x,triangle[1].y);
ctx.lineTo(triangle[2].x,triangle[2].y);
ctx.closePath();
ctx.stroke();
}
function drawMap(){
// Draw the map of my room 400cm * 300cm
ctx.fillStyle = "#ecf0f1"
ctx.beginPath();
ctx.rect(0, 0, 300, 400);
ctx.closePath();
ctx.fill();
drawCircle(A);
drawCircle(B);
drawCircle(C);
}
function drawCircle(c){
ctx.fillStyle = c.color;
ctx.beginPath();
ctx.arc(c.x,c.y,c.r, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
}
// intersection points of 2 circles
function circleIntersections(c0,c1) {
var x0=c0.x;
var y0=c0.y;
var r0=c0.r;
var x1=c1.x;
var y1=c1.y;
var r1=c1.r;
// calc circles' proximity
var dx = x1 - x0;
var dy = y1 - y0;
var d = Math.sqrt((dy*dy) + (dx*dx));
// return if circles do not intersect.
if (d > (r0 + r1)) { return; }
// return if one circle is contained in the other
if (d < Math.abs(r0 - r1)) { return; }
// calc the 2 intersection points
var a = ((r0*r0) - (r1*r1) + (d*d)) / (2.0 * d) ;
var x2 = x0 + (dx * a/d);
var y2 = y0 + (dy * a/d);
var h = Math.sqrt((r0*r0) - (a*a));
var rx = -dy * (h/d);
var ry = dx * (h/d);
var xi = x2 + rx;
var xi_prime = x2 - rx;
var yi = y2 + ry;
var yi_prime = y2 - ry;
return([ {x:xi,y:yi}, {x:xi_prime,y:yi_prime} ]);
}
function ptIsInCircle(pt,circle){
var dx=pt.x-circle.x;
var dy=pt.y-circle.y;
var r=circle.r+1; // allow circle 1px expansion for rounding
return(dx*dx+dy*dy<=r*r);
}
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>

If the centre of the circle is at (x1, y1) and radius is r then the equation of the circle is
(x - x1)^2 + (y - y1)^2 = r^2 (where ^ denotes exponentiation)
For three circles, you will get three equations. Now you have to solve pairwise the equations and get the coordinates.
Note that any two circle, if they intersect, will intersect at two points or meet at a single point. So you will need to define exactly which points of intersection will be used to draw the triangle.
Look at this answer here.

Related

create dynamic line with circles in each end and parameters for width height and rotation for the line - javascript

i need help to create a function to create x quant of lines with circles in each end of the line using parameters to define the angle of rotation, width,height and color of the line and fill the space between the lines, the propours of this is making a kind of rotation max and min angle of the human arm and shoulder.
this is a image of ilustrative example what i need to do, the image of the person model is fine in png i need just to create dynamic lines.
this is the code i have so far:
function drawLine(deg,width,height,canvasId,color){
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
ctx.rotate(deg);
ctx.fillStyle = color;
ctx.fillRect(0, 0, width, height);
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
drawLine(0,200,3,'canvas','red')
drawLine(120,200,3,'canvas1','blue')
canvas{
position: absolute;
}
<canvas id="canvas"></canvas>
<canvas id="canvas1"></canvas>
thanks very much
Based on the picture I will assume 180deg is the reference point of 0. Anything out from there is where we start counting degrees. If that is the case you will want to run a function that calculates the angle between a solid line at 180deg and two other lines from that point.
In total you will need four points. You starting point for all references (pointB in this example), another point (pointD) will be used to set the angle reference to 0 degrees. We will measure the next two angles from this line.
PointA and PointC can be adjusted as needed and we then calculate the angle from pointD/pointB vector. We can use Math.atan2 to calculate the angles of BA and BC move away from BD.
let angle1 = Math.atan2(distBC_x * distBD_y - distBC_y * distBD_x, distBC_x * distBD_x + distBC_y * distBD_y);
In this snippet I changed the color of the lines to make it easier to see what is what. You also won't need to draw the pink line. This is static so you will need to create limits and a dynamic method to change the angles.
Change the x value of pointA and pointC to change the Min and Max. Keep in mind I have to restrictions set for you to be able to switch them.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 500;
//change pointA and pointC x value.
//pointA sould be your Min
//PointC should be your Max
let pointA = {x: 200, y: 250};
let pointB = {x: 250, y: 100}; //common point
let pointC = {x: 120, y: 250};
//only used to set reference to 0 at 180 degrees
let pointD = {x: pointB.x, y: pointB.y + 150};
//creating our vectors length
let distBA_x = pointB.x - pointA.x;
let distBA_y = pointB.y - pointA.y;
let distBC_x = pointB.x - pointC.x;
let distBC_y = pointB.y - pointC.y;
let distBD_x = pointB.x - pointD.x;
let distBD_y = pointB.y - pointD.y;
//calculate angle between pink and purple
let angle1 = Math.atan2(distBC_x * distBD_y - distBC_y * distBD_x, distBC_x * distBD_x + distBC_y * distBD_y);
if(angle1 < 0) {angle1 = angle1 * -1;}
let degree_angle1 = angle1 * (180 / Math.PI);
//calculate angle between purple and red
let angle2 = Math.atan2(distBA_x * distBD_y - distBA_y * distBD_x, distBA_x * distBD_x + distBA_y * distBD_y);
if(angle2 < 0) {angle2 = angle2 * -1;}
let degree_angle2 = angle2 * (180 / Math.PI);
function draw() {
ctx.textStyle = 'black';
ctx.font = '20px Arial';
ctx.fillText('Max = '+ degree_angle1, 100, 20);
ctx.fillText('Min = '+ degree_angle2, 100, 50);
//Lines
ctx.strokeStyle = 'purple';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(pointA.x, pointA.y);
ctx.lineTo(pointB.x, pointB.y);
ctx.stroke();
ctx.strokeStyle = 'red';
ctx.beginPath();
ctx.moveTo(pointB.x, pointB.y);
ctx.lineTo(pointC.x, pointC.y);
ctx.stroke();
ctx.strokeStyle = 'pink';
ctx.beginPath();
ctx.moveTo(pointB.x, pointB.y);
ctx.lineTo(pointD.x, pointD.y);
ctx.stroke();
//Points
ctx.fillStyle = 'purple';
ctx.beginPath();
ctx.arc(pointB.x, pointB.y, 5, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(pointA.x, pointA.y, 5, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.arc(pointC.x, pointC.y, 5, 0, Math.PI*2);
ctx.fill();
ctx.closePath();
//Fill
ctx.fillStyle = 'rgba(113, 0, 158, 0.3)'
ctx.beginPath();
ctx.moveTo(pointA.x, pointA.y);
ctx.lineTo(pointB.x, pointB.y);
ctx.lineTo(pointC.x, pointC.y);
ctx.fill();
ctx.closePath();
}
draw()
<canvas id='canvas'></canvas>

How to get coordinates of every circle from this Canvas

I need to create a pattern where 5 circles connected by lines to a middle main circle.
So I have created dynamically by rotating in some certain angle. Now I need each and every circle's x and y axis coordinates for capturing the click events on every circle.
Please help me how to find out of coordinates of every circle?
var canvas, ctx;
function createCanvasPainting() {
canvas = document.getElementById('myCanvas');
if (!canvas || !canvas.getContext) {
return false;
}
canvas.width = 600;
canvas.height = 600;
ctx = canvas.getContext('2d');
ctx.strokeStyle = '#B8D9FE';
ctx.fillStyle = '#B8D9FE';
ctx.translate(300, 250);
ctx.arc(0, 0, 50, 0, Math.PI * 2); //center circle
ctx.stroke();
ctx.fill();
drawChildCircles(5);
fillTextMultiLine('Test Data', 0, 0);
drawTextInsideCircles(5);
}
function drawTextInsideCircles(n) {
let ang_unit = Math.PI * 2 / n;
ctx.save();
for (var i = 0; i < n; i++) {
ctx.rotate(ang_unit);
//ctx.moveTo(0,0);
fillTextMultiLine('Test Data', 200, 0);
ctx.strokeStyle = '#B8D9FE';
ctx.fillStyle = '#B8D9FE';
}
ctx.restore();
}
function drawChildCircles(n) {
let ang_unit = Math.PI * 2 / n;
ctx.save();
for (var i = 0; i < n; ++i) {
ctx.rotate(ang_unit);
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(100,0);
ctx.arc(200, 0, 40, 0, Math.PI * 2);
let newW = ctx.fill();
ctx.stroke();
}
ctx.restore();
}
function fillTextMultiLine(text, x, y) {
ctx.font = 'bold 13pt Calibri';
ctx.textAlign = 'center';
ctx.fillStyle = "#FFFFFF";
// Defining the `textBaseline`…
ctx.textBaseline = "middle";
var lineHeight = ctx.measureText("M").width * 1.2;
var lines = text.split("\n");
for (var i = 0; i < lines.length; ++i) {
// console.log(lines);
if (lines.length > 1) {
if (i == 0) {
y -= lineHeight;
} else {
y += lineHeight;
}
}
ctx.fillText(lines[i], x, y);
}
}
createCanvasPainting();
<canvas id="myCanvas"></canvas>
The problem here is that you are rotating the canvas matrix and your circles are not aware of their absolute positions.
Why don't you use some simple trigonometry to determine the center of your circle and the ending of the connecting lines ?
function lineToAngle(ctx, x1, y1, length, angle) {
angle *= Math.PI / 180;
var x2 = x1 + length * Math.cos(angle),
y2 = y1 + length * Math.sin(angle);
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
return {x: x2, y: y2};
}
Ref: Finding coordinates after canvas Rotation
After that, given the xy center of your circles, calculating if a coord is inside a circle, you can apply the following formula:
Math.sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)) < r
Ref: Detect if user clicks inside a circle

Create animation with circles time dependent

Hi I try to make a animation. One of the 3 circles which become drawed when the function is called should move from right to left at first one random (yellow, blue or orange) circle should become drawed on the canvas then after 3 seconds the next random circle and then after 2,8 seconds and so far.
How can I do that? Now the circles become drawed every time again when the mainloop starts run again.
window.onload = window.onresize = function() {
var C = 1; // canvas width to viewport width ratio
var el = document.getElementById("myCanvas");
var viewportWidth = window.innerWidth;
var viewportHeight = window.innerHeight;
var canvasWidth = viewportWidth * C;
var canvasHeight = viewportHeight;
el.style.position = "fixed";
el.setAttribute("width", canvasWidth);
el.setAttribute("height", canvasHeight);
var x = canvasWidth / 100;
var y = canvasHeight / 100;
var ballx = canvasWidth / 100;
var n;
window.ctx = el.getContext("2d");
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
// draw triangles
function init() {
ballx;
return setInterval(main_loop, 1000);
}
function drawcircle1()
{
var radius = x * 5;
ctx.beginPath();
ctx.arc(ballx * 108, canvasHeight / 2, radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'yellow';
ctx.fill();
}
function drawcircle2()
{
var radius = x * 5;
ctx.beginPath();
ctx.arc(ballx * 108, canvasHeight / 2, radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'blue';
ctx.fill();
}
function drawcircle3()
{
var radius = x * 5;
ctx.beginPath();
ctx.arc(ballx * 105, canvasHeight / 2, radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'orange';
ctx.fill();
}
function draw() {
var counterClockwise = false;
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
//first halfarc
ctx.beginPath();
ctx.arc(x * 80, y * 80, y * 10, 0 * Math.PI, 1 * Math.PI, counterClockwise);
ctx.lineWidth = y * 1;
ctx.strokeStyle = 'black';
ctx.stroke();
//second halfarc
ctx.beginPath();
ctx.arc(x * 50, y * 80, y * 10, 0 * Math.PI, 1 * Math.PI, counterClockwise);
ctx.lineWidth = y * 1;
ctx.strokeStyle = 'black';
ctx.stroke();
//third halfarc
ctx.beginPath();
ctx.arc(x * 20, y * 80, y * 10, 0 * Math.PI, 1 * Math.PI, counterClockwise);
ctx.lineWidth = y * 1;
ctx.strokeStyle = 'black';
ctx.stroke();
// draw stop button
ctx.beginPath();
ctx.moveTo(x * 87, y * 2);
ctx.lineTo(x * 87, y * 10);
ctx.lineWidth = x;
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x * 95, y * 2);
ctx.lineTo(x * 95, y * 10);
ctx.lineWidth = x;
ctx.stroke();
function drawRandom(drawFunctions){
//generate a random index
var randomIndex = Math.floor(Math.random() * drawFunctions.length);
//call the function
drawFunctions[randomIndex]();
}
drawRandom([drawcircle1, drawcircle2, drawcircle3]);
}
function update() {
ballx -= 0.1;
if (ballx < 0) {
ballx = -radius;
}
}
function main_loop() {
draw();
update();
collisiondetection();
}
init();
function initi() {
console.log('init');
// Get a reference to our touch-sensitive element
var touchzone = document.getElementById("myCanvas");
// Add an event handler for the touchstart event
touchzone.addEventListener("mousedown", touchHandler, false);
}
function touchHandler(event) {
// Get a reference to our coordinates div
var can = document.getElementById("myCanvas");
// Write the coordinates of the touch to the div
if (event.pageX < x * 50 && event.pageY > y * 10) {
ballx += 1;
} else if (event.pageX > x * 50 && event.pageY > y * 10 ) {
ballx -= 1;
}
console.log(event, x, ballx);
draw();
}
initi();
draw();
}
I'm a bit confused by your code, but I think I understand that you want to know how to delay when each circle will start animating to the left.
Here's how to animate your yellow, blue & orange circles with different delays:
Define the 3 circles using javascript objects and store all definintions in an array.
Inside an animation loop:
Calculate how much time has elapsed since the animation began
Loop through each circle in the array
If a circle's delay time as elapsed, animate it leftward
When all 3 circles have moved offscreen-left, stop the animation loop.
Here's annotated code and a Demo:
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasWidth=canvas.width;
var canvasHeight=canvas.height;
// predifine PI*2 because it's used often
var PI2=Math.PI*2;
// startTime is used to calculate elapsed time
var startTime;
// define 3 circles in javascript objects and put
// them in the arcs[] array
var arcs=[];
addArc(canvasWidth,canvasHeight/2,20,0,PI2,0,-1,'yellow');
addArc(canvasWidth,canvasHeight/2+40,20,0,PI2,3000,-1,'blue');
addArc(canvasWidth,canvasHeight/2+80,20,0,PI2,8000,-1,'orange');
// begin animating
requestAnimationFrame(animate);
function animate(time){
// set startTime if it isn't already set
if(!startTime){startTime=time;}
// calc elapsedTime
var elapsedTime=time-startTime;
// clear the canvas
ctx.clearRect(0,0,canvasWidth,canvasHeight);
// assume no further animating is necessary
// The for-loop may change the assumption
var continueAnimating=false;
for(var i=0;i<arcs.length;i++){
var arc=arcs[i];
// update this circle & report if it wasMoved
var wasMoved=update(arc,elapsedTime);
// if it wasMoved, then change assumption to continueAnimating
if(wasMoved){continueAnimating=true;}
// draw this arc at its current position
drawArc(arc);
}
// if update() reported that it moved something
// then request another animation loop
if(continueAnimating){
requestAnimationFrame(animate);
}else{
// otherwise report the animation is complete
alert('Animation is complete');
}
}
function update(arc,elapsedTime){
// has this arc's animation delay been reached by elapsedTime
if(elapsedTime>=arc.delay){
// is this arc still visible on the canvas
if(arc.cx>-arc.radius){
// if yes+yes, move this arc by the specified moveX
arc.cx+=arc.moveX;
// report that we moved this arc
return(true);
}
}
// report that we didn't move this arc
return(false);
}
// create a javascript object defining this arc
function addArc(cx,cy,radius,startAngle,endAngle,
animationDelay,moveByX,color){
arcs.push({
cx:cx,
cy:cy,
radius:radius,
start:startAngle,
end:endAngle,
// this "delay" property is what causes this
// circle to delay before it starts to animate
delay:animationDelay,
moveX:moveByX,
color:color,
});
}
// draw a given arc
function drawArc(a){
ctx.beginPath();
ctx.arc(a.cx,a.cy,a.radius,a.start,a.end);
ctx.fillStyle=a.color;
ctx.fill();
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=400 height=300></canvas>

How can I draw arrows on a canvas with mouse

recently I started playing with canvas element. Now I am able to draw lines(as many as I wish) on a canvas with mouse. You can see it here in the code: https://jsfiddle.net/saipavan579/a6L3ka8p/.
var ctx = tempcanvas.getContext('2d'),
mainctx = canvas.getContext('2d'),
w = canvas.width,
h = canvas.height,
x1,
y1,
isDown = false;
tempcanvas.onmousedown = function(e) {
var pos = getPosition(e, canvas);
x1 = pos.x;
y1 = pos.y;
isDown = true;
}
tempcanvas.onmouseup = function() {
isDown = false;
mainctx.drawImage(tempcanvas, 0, 0);
ctx.clearRect(0, 0, w, h);
}
tempcanvas.onmousemove = function(e) {
if (!isDown) return;
var pos = getPosition(e, canvas);
x2 = pos.x;
y2 = pos.y;
ctx.clearRect(0, 0, w, h);
drawEllipse(x1, y1, x2, y2);
}
function drawEllipse(x1, y1, x2, y2) {
var radiusX = (x2 - x1) * 0.5,
radiusY = (y2 - y1) * 0.5,
centerX = x1 + radiusX,
centerY = y1 + radiusY,
step = 0.01,
a = step,
pi2 = Math.PI * 2 - step;
ctx.beginPath();
ctx.moveTo(x1,y1);
for(; a < pi2; a += step) {
ctx.lineTo(x2,y2);
}
ctx.closePath();
ctx.strokeStyle = '#000';
ctx.stroke();
}
function getPosition(e, gCanvasElement) {
var x;
var y;
x = e.pageX;
y = e.pageY;
x -= gCanvasElement.offsetLeft;
y -= gCanvasElement.offsetTop;
return {x:x, y:y};
};
Now I want to draw arrow headed lines(for pointing to some specific point on a image) in the same way as I am drawing the lines. How can do that? Thank you in advance.
You can draw an arrowhead at the end of line segment [p0,p1] like this:
calculate the angle from p0 to p1 using Math.atan2.
Each side of the arrowhead starts at p1, so calculate the 2 arrow endpoints using trigonometry.
draw the [p0,p1] line segment and the 2 arrowhead line segments.
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var p0={x:50,y:100};
var p1={x:250,y:50};
drawLineWithArrowhead(p0,p1,15);
function drawLineWithArrowhead(p0,p1,headLength){
// constants (could be declared as globals outside this function)
var PI=Math.PI;
var degreesInRadians225=225*PI/180;
var degreesInRadians135=135*PI/180;
// calc the angle of the line
var dx=p1.x-p0.x;
var dy=p1.y-p0.y;
var angle=Math.atan2(dy,dx);
// calc arrowhead points
var x225=p1.x+headLength*Math.cos(angle+degreesInRadians225);
var y225=p1.y+headLength*Math.sin(angle+degreesInRadians225);
var x135=p1.x+headLength*Math.cos(angle+degreesInRadians135);
var y135=p1.y+headLength*Math.sin(angle+degreesInRadians135);
// draw line plus arrowhead
ctx.beginPath();
// draw the line from p0 to p1
ctx.moveTo(p0.x,p0.y);
ctx.lineTo(p1.x,p1.y);
// draw partial arrowhead at 225 degrees
ctx.moveTo(p1.x,p1.y);
ctx.lineTo(x225,y225);
// draw partial arrowhead at 135 degrees
ctx.moveTo(p1.x,p1.y);
ctx.lineTo(x135,y135);
// stroke the line and arrowhead
ctx.stroke();
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>

How to draw polygons on an HTML5 canvas?

I need to know how to draw polygons on a canvas. Without using jQuery or anything like that.
Create a path with moveTo and lineTo (live demo):
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#f00';
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(100,50);
ctx.lineTo(50, 100);
ctx.lineTo(0, 90);
ctx.closePath();
ctx.fill();
from http://www.scienceprimer.com/drawing-regular-polygons-javascript-canvas:
The following code will draw a hexagon. Change the number of sides to create different regular polygons.
var ctx = document.getElementById('hexagon').getContext('2d');
// hexagon
var numberOfSides = 6,
size = 20,
Xcenter = 25,
Ycenter = 25;
ctx.beginPath();
ctx.moveTo (Xcenter + size * Math.cos(0), Ycenter + size * Math.sin(0));
for (var i = 1; i <= numberOfSides;i += 1) {
ctx.lineTo (Xcenter + size * Math.cos(i * 2 * Math.PI / numberOfSides), Ycenter + size * Math.sin(i * 2 * Math.PI / numberOfSides));
}
ctx.strokeStyle = "#000000";
ctx.lineWidth = 1;
ctx.stroke();
#hexagon { border: thin dashed red; }
<canvas id="hexagon"></canvas>
//poly [x,y, x,y, x,y.....];
var poly=[ 5,5, 100,50, 50,100, 10,90 ];
var canvas=document.getElementById("canvas")
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#f00';
ctx.beginPath();
ctx.moveTo(poly[0], poly[1]);
for(let item=2 ; item < poly.length-1 ; item+=2 ){ctx.lineTo( poly[item] , poly[item+1] )}
ctx.closePath();
ctx.fill();
//create and fill polygon
CanvasRenderingContext2D.prototype.fillPolygon = function (pointsArray, fillColor, strokeColor) {
if (pointsArray.length <= 0) return;
this.moveTo(pointsArray[0][0], pointsArray[0][1]);
for (var i = 0; i < pointsArray.length; i++) {
this.lineTo(pointsArray[i][0], pointsArray[i][1]);
}
if (strokeColor != null && strokeColor != undefined)
this.strokeStyle = strokeColor;
if (fillColor != null && fillColor != undefined) {
this.fillStyle = fillColor;
this.fill();
}
}
//And you can use this method as
var polygonPoints = [[10,100],[20,75],[50,100],[100,100],[10,100]];
context.fillPolygon(polygonPoints, '#F00','#000');
Here is a function that even supports clockwise/anticlockwise drawing do that you control fills with the non-zero winding rule.
Here is a full article on how it works and more.
// Defines a path for any regular polygon with the specified number of sides and radius,
// centered on the provide x and y coordinates.
// optional parameters: startAngle and anticlockwise
function polygon(ctx, x, y, radius, sides, startAngle, anticlockwise) {
if (sides < 3) return;
var a = (Math.PI * 2)/sides;
a = anticlockwise?-a:a;
ctx.save();
ctx.translate(x,y);
ctx.rotate(startAngle);
ctx.moveTo(radius,0);
for (var i = 1; i < sides; i++) {
ctx.lineTo(radius*Math.cos(a*i),radius*Math.sin(a*i));
}
ctx.closePath();
ctx.restore();
}
// Example using the function.
// Define a path in the shape of a pentagon and then fill and stroke it.
context.beginPath();
polygon(context,125,125,100,5,-Math.PI/2);
context.fillStyle="rgba(227,11,93,0.75)";
context.fill();
context.stroke();
In addition to #canvastag, use a while loop with shift I think is more concise:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var poly = [5, 5, 100, 50, 50, 100, 10, 90];
// copy array
var shape = poly.slice(0);
ctx.fillStyle = '#f00'
ctx.beginPath();
ctx.moveTo(shape.shift(), shape.shift());
while(shape.length) {
ctx.lineTo(shape.shift(), shape.shift());
}
ctx.closePath();
ctx.fill();
You can use the lineTo() method same as:
var objctx = canvas.getContext('2d');
objctx.beginPath();
objctx.moveTo(75, 50);
objctx.lineTo(175, 50);
objctx.lineTo(200, 75);
objctx.lineTo(175, 100);
objctx.lineTo(75, 100);
objctx.lineTo(50, 75);
objctx.closePath();
objctx.fillStyle = "rgb(200,0,0)";
objctx.fill();
if you not want to fill the polygon use the stroke() method in the place of fill()
You can also check the following: http://www.authorcode.com/draw-and-fill-a-polygon-and-triangle-in-html5/
thanks
For the people looking for regular polygons:
function regPolyPath(r,p,ctx){ //Radius, #points, context
//Azurethi was here!
ctx.moveTo(r,0);
for(i=0; i<p+1; i++){
ctx.rotate(2*Math.PI/p);
ctx.lineTo(r,0);
}
ctx.rotate(-2*Math.PI/p);
}
Use:
//Get canvas Context
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.translate(60,60); //Moves the origin to what is currently 60,60
//ctx.rotate(Rotation); //Use this if you want the whole polygon rotated
regPolyPath(40,6,ctx); //Hexagon with radius 40
//ctx.rotate(-Rotation); //remember to 'un-rotate' (or save and restore)
ctx.stroke();
To make a simple hexagon without the need for a loop, Just use the beginPath() function. Make sure your canvas.getContext('2d') is the equal to ctx if not it will not work.
I also like to add a variable called times that I can use to scale the object if I need to.This what I don't need to change each number.
// Times Variable
var times = 1;
// Create a shape
ctx.beginPath();
ctx.moveTo(99*times, 0*times);
ctx.lineTo(99*times, 0*times);
ctx.lineTo(198*times, 50*times);
ctx.lineTo(198*times, 148*times);
ctx.lineTo(99*times, 198*times);
ctx.lineTo(99*times, 198*times);
ctx.lineTo(1*times, 148*times);
ctx.lineTo(1*times,57*times);
ctx.closePath();
ctx.clip();
ctx.stroke();
Let's do that with HTML and get that down to this:
<!DOCTYPE html>
<html>
<head>
<title> SVG hexagon </title>
</head>
<body>
<svg width="300" height="110" >
<polygon point="50 3, 100 28, 100 75, 50 100, 3 75, 3 25" stroke="red" fill="lime" stroke-width="5"/>
</svg>
</body>
</html>
var ctx = document.getElementById('hexagon').getContext('2d');
// hexagon
var numberOfSides = 4,
size = 25,
Xcenter = 40,
Ycenter = 40;
ctx.beginPath();
ctx.moveTo (Xcenter + size * Math.cos(0), Ycenter + size * Math.sin(0));
for (var i = 1; i <= numberOfSides;i += 1) {
ctx.lineTo (Xcenter + size * Math.cos(i * 2 * Math.PI / numberOfSides), Ycenter + size * Math.sin(i * 2 * Math.PI / numberOfSides));
}
ctx.strokeStyle = "#000000";
ctx.lineWidth = 1;
ctx.stroke();
#hexagon { border: thin dashed red; }
<canvas id="hexagon"></canvas>

Categories

Resources