I want to create a canvas with a circle, and inside the circle should be a triangle. I know how to draw a simple circle (below), but how do I put in the triangle?
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.beginPath();
context.arc(75,100,55,0,2 * Math.PI);
context.stroke();
Add these lines before calling stroke
context.moveTo(75,75);
context.lineTo(100, 100);
context.lineTo(25,150);
context.lineTo(75,75);
It is coming out of the cirle a little bit, but you get the idea.
In order to draw a triangle inside a circle you need to calculate the positions of the vertices. Supposing that your triangle is equilateral the angle between vertices is 120degs or 2*Math.PI/3:
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
let cw = canvas.width = 300;// the width of the canvas
let ch = canvas.height = 300;// the height of the canvas
let c={// the circle: coords of the center and the radius
x:75,y:100,r:55
}
let angle = (2*Math.PI)/3;// the angle between vertices
points = [];// the vertices array
for(let i = 0; i < 3; i++){
let o = {}
o.x = c.x + c.r*Math.cos(i*angle);
o.y = c.y + c.r*Math.sin(i*angle);
points.push(o);
}
// draw the circle
context.beginPath();
context.arc(c.x,c.y,c.r,0,2 * Math.PI);
context.stroke();
// draw the triangle
context.beginPath();
context.moveTo(points[0].x,points[0].y);
for(let i = 1; i < points.length; i++){
context.lineTo(points[i].x,points[i].y);
}
context.closePath();
context.stroke();
canvas{border:1px solid}
<canvas id="myCanvas"></canvas>
Related
I'm trying to rotate a triangle around a circle, the triangle should always face outwards, meaning it should rotate around the circle, AND around its center I'm guessing.
I found this question, which is something like what I need, but just in reverse.
Another thing I need is to have the triangle pointed at the user's mouse coords. aka the triangle is something like an arrow.
I just edited the code you linked and replaced the rectangle with a triangle, and animate() with a mouse move listener, of course:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cx = 100;
var cy = 100;
var radious = 10;
var gap = 5;
var triangleHeight = 25;
var triangleBase = 10;
redraw(cx + 1, cy);
function redraw(mx, my)
{
mox = mx-cx;
moy = my-cy;
rotation = Math.atan2(moy, mox);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(cx, cy, radious, 0, Math.PI * 2);
ctx.closePath();
ctx.fill();
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(rotation);
ctx.beginPath();
ctx.moveTo(radious+gap, -triangleBase/2);
ctx.lineTo(radious+gap, triangleBase/2);
ctx.lineTo(radious+gap+triangleHeight, 0);
ctx.lineTo(radious+gap, -triangleBase/2)
ctx.stroke();
ctx.restore();
}
canvas.addEventListener("mousemove", function (e) {
redraw(e.pageX, e.pageY);
}, false);
<canvas id="canvas"></canvas>
BTW, it's my very first piece of code in JS, so, feel free to correct my code if something is funny.
I've been experimenting with the HTML Canvas for weeks, and I use .arc to make circles, but when the circle is incomplete, it doesn't show like a piece of pie. Instead, it uses the shortest distance possible from one end to the other, and it fills the rest! Is there a way for it to show up as pie pieces?
Here's an example using .arc:
<html>
<head>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(100, 75, 50, 0, 2) //supposedly radians for 2
ctx.stroke();
ctx.fillStyle = "black";
ctx.fill();
</head>
<body>
<canvas id="canvas" width="1000" height="600"></canvas>
</body>
</html>
So what happens is that .arc() literally creates a angled path from your provided x and y coordinates. What you need to do is:
move your 'drawing pointer' where you want to place the circle
make a 'path' from that position, which is the center of your circle
draw the actual pie arc
go back to your circle to close that path.
The following code illustrates a working example of this:
const WIDTH = 100;
const HEIGHT = 100;
const RADIUS = 50;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = WIDTH;
canvas.height = HEIGHT;
document.body.appendChild(canvas);
// identify center of your circle for learning purposes
// let's use the center of the canvas:
const [dx, dy] = [WIDTH / 2, HEIGHT / 2];
context.fillStyle = 'orange';
context.fillRect(dx, dy, 5, 5);
// clean / begin your paths
context.beginPath();
// move to (and start your path to) your position:
context.moveTo(dx, dy);
// create a circle using the dx,dy as the center of the circle:
const startAngleInRadians = 0;
const endAngleInRadians = Math.PI * 0.5;
const goAntiClockwise = false;
context.arc(dx, dy, RADIUS, startAngleInRadians, endAngleInRadians, goAntiClockwise);
// move back to your position (not required if you only draw 1 pie since your paths dont change):
context.moveTo(dx, dy);
// let's fill our pie with a pink color!:
context.fillStyle = '#FF00FF55';
context.fill();
To illustrate what is actually happening I made a simple canvas animation:
const WIDTH = 200;
const HEIGHT = 200;
const RADIUS = 50;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const [dx, dy] = [0, 0];
canvas.width = WIDTH;
canvas.height = HEIGHT;
document.body.appendChild(canvas);
context.strokeStyle = 'red';
function sleep(timeout) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(true);
}, timeout);
});
}
async function showHowItWorks() {
// move from arc center to the arc start position:
for (let i=0; i<RADIUS; i++) {
context.beginPath();
context.moveTo(dx, dy);
context.lineTo(dx + i, dy);
context.stroke();
await sleep(50);
}
// draw the arc from start position to arc end:
const angle = Math.PI * 0.5;
for (let i=0; i<angle; i+=0.05) {
context.beginPath();
context.arc(dx, dy, RADIUS, 0, i, false);
context.stroke();
await sleep(50);
}
// move from arc end back to the arc center:
for (let i=50; i>=0; i--) {
context.moveTo(dx, dy + RADIUS);
context.lineTo(dx, dy + i);
context.stroke();
await sleep(50);
}
}
showHowItWorks();
Of course, there are some flaws: I am not sure whether the .arc() command moves the 'drawing pointer' -like .moveTo()- or draws from the position to the arc -like .lineTo()-.
In the first case, the pointer jumps from your center position to the arc. In the second case it actually creates a line from your center towards the arc. But anyway, both ways will give you the same end result in most cases.
I am having some trouble drawing lines in circle with html5 canvas.
I am trying to make the bars look something like this
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var bars = 50;
var radius = 100;
for(var i = 0; i < bars; i++){
var x = radius*Math.cos(i);
var y = radius*Math.sin(i);
draw_rectangle(x+200,y+200,1,13,i, ctx );
}
function draw_rectangle(x,y,w,h,deg, ctx){
ctx.save();
ctx.translate(x, y);
ctx.rotate(degrees_to_radians(deg));
ctx.fillStyle = "yellow";
ctx.fillRect(-1*(w/2), -1*(h/2), w, h);
ctx.restore();
}
function degrees_to_radians(degrees){
return degrees * Math.PI / 180;
}
function radians_to_degrees(radians){
return radians * 180 / Math.PI;
};
for some reason my lines are all crooked and unaligned. I really need help on this one. https://codepen.io/anon/pen/PRBdYV
The easiest way to deal with such a visualization is to play with the transformation matrix of your context.
You need to understand it as if you were holding a sheet of paper in your hands.
Instead of trying to draw the lines at the correct angle, rotate the sheet of paper, and always draw your lines in the same direction.
This way all you need in your drawing method is the angle, and the height of each bar.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
// the position of the whole thing
var circleX = canvas.width / 2;
var circleY = canvas.height / 2;
//
var bars = 50;
var barWidth = 5;
// inner radius
var radius = 50;
ctx.fillStyle = "yellow";
// no need to use degrees, a full circle is just 2π
for(var i = 0; i < Math.PI*2; i+= (Math.PI*2 / bars)){
draw_rectangle(i, (Math.random()*30) + 10);
}
function draw_rectangle(rad, barHeight){
// reset and move to the center of our circle
ctx.setTransform(1,0,0,1, circleX, circleY);
// rotate the context so we face the correct angle
ctx.rotate(rad);
// move along y axis to reach the inner radius
ctx.translate(0, radius);
// draw the bar
ctx.fillRect(
-barWidth/2, // centered on x
0, // from the inner radius
barWidth,
barHeight // until its own height
);
}
canvas#canvas{
background:black;
}
<html>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
</body>
</html>
https://codepen.io/anon/pen/YajONR
Problems fixed: Math.cos wants radians, not degrees
We need to go from 0 to 360, so I adjusted the number of bars to make that a bit easier, and multiplied i by 6 (so the max value is 60*6==360)
If we don't add +90 when drawing the bars, we just get a circle
Check your codepen and figured out the problem lies in the degrees_to_radians
Here is the update link of you code.Link
PS I only looked at the shape of the circle not alignments of the bar :D
I'm trying to animate polygons made using lineTo in canvas. It shows up, but won't move. I tried to follow the object approach, but it didn't seem to do anything.
Help?
<!doctype html>
<html>
<head>
<style>
canvas {
border: 1px solid black;
}
</style>
<script>
"use strict";
var canvas;
var ctx;
var timer;
var shapes;
var x;
var y;
function degreesToRadians(degrees) {
return (degrees*Math.PI)/180;
}
//to rotate stuff, not currently in use
function rotateStuff() {
roTimer = setInterval(ctx.rotate(degreesToRadians(60)),100);
}
//constructor for Shape object, not currently in use
function Shape() {
//this.x = canvas.width/2 + Math.random()*10-5;
//this.y = canvas.height/2 + Math.random()*10-5;
this.r = Math.random()*20-5;
this.vx = Math.random()*10-5;
this.vy = Math.random()*10-5;
var colors = ['red','green','orange','purple','blue','aqua','pink','gold'];
this.color = colors[Math.floor(Math.random()*colors.length)];
}
//pushes the shapes to an array, not currently in use
function makeShapes() {
shapes = [];
for (var i = 0; i<2; i++){
shapes.push(new Shape());
}
}
//fills and resets background
function fillBackground() {
ctx.globalCompositeOperation = 'source-over';
ctx.fillStyle = 'rgba(0,0,0,0.3)';
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.globalCompositeOperation = 'lighter';
}
//draws the shape
function drawShapes(r, p, m) {
//canvas, x position, y position, radius, number of points, fraction of radius for inset
fillBackground();
x = 350;
y = 350;
r = Math.random()*20-5;
//for (var i = 0; i < shapes.length; i++) {
//var s = shapes[i];
ctx.save();
ctx.beginPath();
ctx.translate(x, y);
ctx.moveTo(0,0-r);
//}
for (var i2 = 0; i2 < p; i2++) {
ctx.rotate(Math.PI / p);
ctx.lineTo(0, 0 - (r*m));
ctx.rotate(Math.PI / p);
ctx.lineTo(0, 0 - r);
}
ctx.fillStyle = "yellow";
ctx.fill();
var vx = Math.random()*10-5;
var vy = Math.random()*10-5;
x += vx;
y += vy;
r -=8
ctx.restore();
}
//}
window.onload = function() {
canvas = document.getElementById('animCanvas');
ctx = canvas.getContext('2d');
//makeShapes();
//console.log(shapes);
timer = setInterval(drawShapes(40, 5, 0.5), 100);
//timer2 = setInterval(makeShapes, 4500);
}
</script>
</head>
<body>
<canvas width='700' height='700' id='animCanvas'></canvas>
</body>
</html>
A coding hint: Separate your code into discrete duties. This separation lets you concentrate your coding focus on simpler tasks. And once you've got that task running correctly you can move onto another task without worrying that a previous task has become broken.
Here are the tasks for your "rotate stars" project
1. Draw a star and
2. Rotate that star using animation.*
... and their descriptions
drawShapes() draws one star at a specified [x,y] position at a specified currentAngle
animate() runs an animation loop that:
Clears the canvas.
Fills the background.
Draws the star (or many stars) with `drawShapes`.
Changes the `currentAngle` rotation for the next loop.
Requests another animation loop.
About rotating
Rotating your shape is a simple 2 step process:
1. Move to the shape's centerpoint: `.translate(centerX,centerY)'
2. Rotate the canvas to the currently desired angle: `rotate(currentAngle)`
Since translate and rotate are not automatically undone, you must "clean up" after your transformations. An easy way to do that is to do this: context.setTransform(1,0,0,1,0,0). This sets the internal transformation matrix to its default state (==fully untransformed).
So your rotation process becomes:
1. Move to the shape's centerpoint: `.translate(centerX,centerY)'
2. Rotate the canvas to the currently desired angle: `.rotate(currentAngle)`
3. Reset the canvas: `.setTransform(1,0,0,1,0,0)`
Here's annotated code and a Demo:
var canvas;
var ctx;
canvas = document.getElementById('animCanvas');
ctx = canvas.getContext('2d');
var cw=canvas.width;
var ch=canvas.height;
var shapes=[];
var star1={ x:50, y:100, r:40, currentAngle:0, p:5, m:.5, fill:'yellow',angleChange:Math.PI/60}
var star2={ x:150, y:100, r:25, currentAngle:0, p:55, m:5, fill:'blue',angleChange:-Math.PI/360}
var star3={ x:250, y:100, r:25, currentAngle:0, p:15, m:3, fill:'red',angleChange:Math.PI/120}
requestAnimationFrame(animate);
function drawShapes(star) {
ctx.save();
// translate to the star's centerpoint
ctx.translate(star.x,star.y);
// rotate to the current angle
ctx.rotate(star.currentAngle)
// draw the star
ctx.beginPath();
ctx.moveTo(0,0-star.r);
for (var i2 = 0; i2 < star.p; i2++) {
ctx.rotate(Math.PI / star.p);
ctx.lineTo(0, 0 - (star.r*star.m));
ctx.rotate(Math.PI / star.p);
ctx.lineTo(0, 0 - star.r);
}
ctx.fillStyle =star.fill;
ctx.fill();
ctx.restore();
}
function fillBackground() {
ctx.globalCompositeOperation = 'source-over';
ctx.fillStyle = 'rgba(0,0,0,0.3)';
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.globalCompositeOperation = 'lighter';
}
function animate(time){
// clear the canvas
ctx.clearRect(0,0,cw,ch);
// fill the background
fillBackground();
// draw the stars
// If you put star1,star2,star3 in a stars[] array then
// you could simply the following demo code by looping
// through the array
//
// draw the star1
drawShapes(star1);
// increase star1's current rotation angle
star1.currentAngle+=star1.angleChange;
// draw the star2
drawShapes(star2);
// increase star2's current rotation angle
star2.currentAngle+=star2.angleChange;
// draw the star3
drawShapes(star3);
// increase star3's current rotation angle
star3.currentAngle+=star2.angleChange;
// request another animation loop
requestAnimationFrame(animate);
}
<canvas width='700' height='700' id='animCanvas'></canvas> </body>
You can draw arcs and you can draw images on a canvas using javascript, but is there anyway to do both? that is, is there anyway to draw an image as the arc instead of a solid line?
If not, is there a seperate way to arc an image?
I tried doing a pixel-by-pixel transformation of the image along the points of an arc, but it ended up being very slow and looking pretty poor since I can't directly get pixel data from javascript (or can you? I didnt see a way) so for each pixel, I needed to calculate the point along the arc, draw the current image pixel, refetch it, draw the image data to the calculated point, then clear that point on the canvas.
Have you tried setting the strokeStyle to a CanvasPattern based on an image? It looks like you could do something like this (assuming img is an HTMLImageElement that you want to draw from and ctx is a CanvasRenderingContext2D):
var pattern = ctx.createPattern(img, "repeat");
ctx.strokeStyle = pattern;
ctx.beginPath();
ctx.arc(123, 408, 80, 0, 1.5*Math.PI, false);
ctx.stroke();
Use this html to create arc : -
<canvas id="myCanvas" width="578" height="250"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = .8 * Math.PI;
var endAngle = 2.2 * Math.PI;
var counterClockwise = false;
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
context.lineWidth = 30;
// line color
context.strokeStyle = 'blue';
context.stroke();
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 8 * Math.PI;
var endAngle =2.3 * Math.PI;
var counterClockwise = false;
context.beginPath();
context.arc(x, y, radius, startAngle, endAngle, counterClockwise);
context.lineWidth = 30;
// line color
context.strokeStyle = 'red';
context.stroke();
</script>