I'm trying to create an Arc in canvas, and I want to use degrees, instead of radians.
The problem is that it is not starting at 12 o'clock, but at 3 o'clock, just like the documentation has said, but how can I force it to 12?
JsFiddle: http://jsfiddle.net/C8CXz/
function degreesToRadians (degrees) {
return degrees * (Math.PI/180);
}
function radiansToDegrees (radians) {
return radians * (180/Math.PI);
}
var canvas = document.getElementById('circle');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(80, 80, 50, degreesToRadians(0), degreesToRadians(180), false);
ctx.lineWidth = 10;
ctx.stroke();
Subtract half PI to both start and end point when drawing the arc, like this:
...
ctx.arc(80, 80, 50, degreesToRadians(0)-Math.PI/2, degreesToRadians(180)-Math.PI/2, false);
...
Here is the Fiddle.
Related
I need to draw a perfect curve / parabola in an html5 canvas. The 3 {x;y} coordinates of the points are given. I tried with a bezierCurveTo or a quadraticCurveTo, but the curve won't go in the middle point.
The result I want ( the blue doted curve, and the blue one ) : Wanted result
The result I have : Current result
Code :
ctx.strokeStyle = '#00478a';
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.moveTo(x1AtRatio, 30);
ctx.quadraticCurveTo(criticalSectionAtRatio, 100, x2AtRatio, 30);
ctx.stroke();
Where x1AtRatio - x2AtRatio - criticalSectionAtRatio are the given x by user input and 30 - 100 - 30 are the y
Control points define slopes
You will need to use two beziers as the curve will not pass through the control point.
The control points set the slopes of the curve out from the last point and in to the next point.
The example (below) draws a parabola using two curves. The function drawCurve()
I draw it twice once scaled and once normal.
Control points are blue.
The three points on the curve are red
The slopes are in green.
For example
const ctx = canvas.getContext("2d");
// drawScaled
ctx.setTransform(2,0,0,2,-50, -55);
drawAll();
// without scale
ctx.setTransform(1,0,0,1,-50, 0);
drawAll();
function drawCurve() {
ctx.beginPath();
ctx.strokeStyle = "#000";
ctx.moveTo(100 - 30, 30); // start left side
ctx.quadraticCurveTo(
100 - 30 / 2, 100, // controls point sets slope out from start and into center
100, 100 // center point
);
ctx.quadraticCurveTo(
100 + 30 / 2, 100, // control point sets slope out from center and into last point
100 + 30, 30 // last point
);
ctx.stroke();
}
function drawAll() {
// points on curve
drawPoint(100-30, 30);
drawPoint(100, 100);
drawPoint(100+30, 30);
// Control points
drawPoint(100 - 30 / 2, 100, "#00F");
drawPoint(100 + 30 / 2, 100, "#00F");
// Draw line through all points to show slopes
drawLine(100-30, 30, 100 - 30 / 2, 100);
drawLine(100 - 30 / 2, 100, 100, 100);
drawLine(100, 100, 100 + 30 / 2, 100);
drawLine(100 + 30 / 2, 100, 100 + 30, 30);
// Draw curve
drawCurve();
}
function drawPoint(x,y,col = "red") {
ctx.fillStyle = col;
ctx.beginPath();
ctx.arc(x, y, 2, 0, Math.PI * 2);
ctx.fill();
}
function drawLine(x,y, x1, y1, col = "#0A08") {
ctx.strokeStyle = col;
ctx.beginPath();
ctx.lineTo(x, y);
ctx.lineTo(x1, y1);
ctx.stroke();
}
canvas {
border: 1px solid black;
}
<canvas id="canvas"></canvas>
I want draw something like this in javascript:
Example:
The bigger circle: r = 5
What do I want to do? to position circles by forming a circle
My questions are (I would like to know):
How much points can I draw on a circle if I know the ray,
the distance between each circle and the radius of each circle?
How can I find the position of each circle (to draw automatically)?
Like the question 1 but the circles do not have the same radius.
Thank you!
Displace points around a circle edge equidistantly
Using HTML Canvas and a bit of trigonometry
Create a reusable circles() function and pass the desired arguments for Number of circles, Size, Radius, Color:
const ctx = document.getElementById("canvas").getContext("2d");
const cvsSize = 400;
ctx.canvas.width = cvsSize;
ctx.canvas.height = cvsSize;
function circles(tot, rad, dist, color) {
const arc = Math.PI * 2 / tot; // Arc in Radians
let ang = 0; // Start at angle 0 (East)
for (let i = 0; i < tot; i++) {
const x = dist * Math.cos(ang) + (cvsSize / 2);
const y = dist * Math.sin(ang) + (cvsSize / 2);
ctx.beginPath();
ctx.arc(x, y, rad, 0, Math.PI * 2, false);
ctx.fillStyle = color;
ctx.fill();
ctx.closePath();
ang += arc;
}
}
// Circles, Radius, Distance, Color
circles(3, 5, 10, "#f0b");
circles(10, 8, 50, "#0bf");
circles(17, 10, 90, "#bf0");
circles(21, 15, 140, "#b0f");
<canvas id="canvas"></canvas>
Hi I am having a problem with drawing a graph. The situation is there are number of days remaining and I need to draw and arc
var eAngle = tax * 0.0172;
var c = document.getElementById("tax");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(100,100,70,1.5 , Math.PI * eAngle, true);
ctx.stroke();
Also how can I write some text in the middle of that arc circle.
I have adjusted the code a little bit. First of, we need to know the angle every day in your year gets. I'm going to say that would be a full circle (Math.PI * 2) divided by 365 (or 366 when its one-of-those-years). Then it is a matter of correctly understanding the arc function:
arc(x, y, radius, angle (0 = x-axis to the right), end angle (starting x-axis where 1 radian is a full circle), counterclockwise (true is counterclockwise drawing from start until the end angle, and false or ommitting is the regular clockwise angle);
In the end, this will work:
context.arc(100, 100, 50, -Math.PI / 2, -Math.PI / 2 + day * (Math.PI * 2 / 365), false);
Where, in order, the arguments are: x-position, y-position, radius, -90 degrees (to start from the y-axis instead of the x), whatever this outputs when you input a day plus the offset of the previous argument.
To draw text on top of this., you can simply use the canvas fillText function.
var dayArc = Math.PI * 2 / 365;
var dayN = 0;
var offset = -Math.PI / 2;
var canvas = document.getElementById("tax")
var context = canvas.getContext('2d');
setInterval(function(){
dayN = dayN > 364 ? 0 : dayN+1;
canvas.width = 500;
context.beginPath();
context.arc(100, 100, 50, offset, offset + dayN * dayArc, false);
context.stroke();
context.textAlign = 'center';
context.font = "24px 'Helvetica Neue', sans-serif";
context.fillText((365-dayN) + '/365', 100, 110);
}, 1000 / 60);
<canvas id="tax" widht="500" height="500"></canvas>
Okay. So I would split up the calculations, to make it clearer what's going on. We know that a full circle is Math.PI * 2 radians. So we keep that separate.
Since we only want a fraction of a circle, representing the number of days out of a year, we keep a separate variable, say, fractionOfCircle, and then multiply them for our final result.
var fractionOfCircle = days / 365;
var canvas = document.getElementById("tax");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(100, 100, 70, 1.5, Math.PI * 2 * fractionOfCircle, true);
ctx.stroke();
To put a text within the circle, my first approach would be to overlay an HTML element, like a div, and position the text accordingly.
I have this animation, but i cant get over the logic. I hope someone can help me here.
Basicly i need this: http://jsfiddle.net/PDE85/9/ but without the arrow doing such crazy moves. It should be attached to the front of the open circle to simulate an expanding arrow.
I got the triangle to turn right here but it doesnt work when i mix it with position logic as seen in the first example.
Here is the code for reference
(function() {
var size = ($(window).height()/5)*4;
$("#intro-container").css('width',size);
$("#intro-canvas").css('width',size);
$("#intro-canvas").css('height',size);
var interval = window.setInterval(draw, 30);
var degrees = 0.0;
var offset = 20;
var rotate = 0;
var canvas = document.getElementById('intro-canvas');
var ctx = canvas.getContext('2d');
canvas.width = size;
canvas.height = size;
draw();
function draw() {
if (canvas.getContext) {
ctx.fillStyle="white";
ctx.strokeStyle="white";
ctx.clearRect(0, 0, size, size);
ctx.save();
ctx.translate(size/2, size/2);
ctx.rotate(-90 * Math.PI / 180);
ctx.beginPath();
ctx.lineWidth = size/8;
ctx.arc(0, 0, size/3, 0, rotate * Math.PI / 180);
//ctx.shadowBlur=1;
//ctx.shadowColor="black";
ctx.stroke();
ctx.restore();
ctx.beginPath();
ctx.save();
// moving logic
ctx.translate(size/2, size/2);
ctx.rotate(-Math.PI / 180 * -rotate+1);
ctx.translate(-size/3, -size/3);
// rotating logic
ctx.translate(size/2, size/2);
ctx.rotate((rotate * Math.PI + 420) / 180);
ctx.moveTo(0,0);
ctx.lineTo(size/6,0);
ctx.lineTo(0,size/6);
ctx.lineTo(0,0);
ctx.fill();
ctx.restore();
rotate += 1;
if(rotate > 360){
window.clearInterval(interval)
}
}
}
})();
I believe you are looking for this : http://jsfiddle.net/PDE85/12/
The rotation comes from, the rotate call which is unnecessary.
Plus you need an inverted triangle, hence the coordinates needed an update:
...
// ctx.rotate((rotate * Math.PI + 420) / 180);
ctx.moveTo(0,0);
ctx.lineTo(-size/6,0);
ctx.lineTo(0,-size/6);
...
Here is an example!
I am trying to reset the green arc inside drawValueArc() so that each time you click the change button, the green arc is removed and redrawn. How can I remove it without removing the entire canvas? Also, as an aside, I have noticed that Math.random() * 405 * Math.PI / 180 doesn't actually always result in an arc that fits inside the gray arc, sometimes it is larger than the gray arc, why is this?
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cx = 150;
var cy = 150;
var startRadians = 135 * Math.PI / 180;
var endRadians = 405 * Math.PI / 180;
//main arc
ctx.beginPath();
ctx.arc(cx, cy, 58, startRadians, endRadians, false);
ctx.strokeStyle="rgb(220,220,220)";
ctx.lineWidth = 38;
ctx.stroke();
$('#setRandomValue').click(function(){
drawValueArc(Math.random() * 405 * Math.PI / 180);
});
function drawValueArc(val){
//ctx.clearRect(0, 0, W, H);
ctx.beginPath();
ctx.arc(cx, cy, 58, startRadians, val, false);
ctx.strokeStyle = "green";
ctx.lineWidth = 38;
ctx.stroke();
}
Drawing past boundary
The problem you are facing is in first instance the fact you are drawing before and after a 0-degree on the circle. This can be complicated to handle as you need to split in two draws: one for the part up to 0 (360) and one 0 to the remaining part.
There is a simple trick you can use to make this easier to deal with and that is to deal with all angles from 0 and use an offset when you draw.
Demo using redraw base (I moved it to jsfiddle as jsbin did not work for me):
http://jsfiddle.net/3dGLR/
Demo using off-screen canvas
http://jsfiddle.net/AbdiasSoftware/Dg9Jj/
First, some optimizations and settings for the offset:
var startRadians = 0; //just deal with angles
var endRadians = 300;
var deg2rad = Math.PI / 180; //pre-calculate this to save some cpu cycles
var offset = 122; //adjust this to modify rotation
We will now let the main function, drawArc() do all calculations for us so we can focus on the numbers - here we also offset the values:
function drawArc(color, start, end) {
ctx.beginPath();
ctx.arc(cx, cy, 58,
(startRadians + offset) * deg2rad,
(end + offset) * deg2rad, false);
ctx.strokeStyle = color;
ctx.lineWidth = 38;
ctx.stroke();
}
Clearing the previous arc
There are several techniques to clear the previous drawn arc:
You can draw the base arc to an off-screen canvas and use drawImage() to erase the old.
You can do as in the following example, just re-draw it with the base color
As with 2. but subtracting the green arc and draw the base color from the end of the green arc to the end of the base arc.
clearing the whole canvas with fillRect or clearRect.
1 and 3 are the fastest, while 4 is the slowest.
With out re-factored function (drawArc) it's as easy as this:
function drawValueArc(val) {
drawArc("rgb(220,220,220)", startRadians, endRadians);
drawArc("green", startRadians, val);
}
As everything now is 0-based concerning start we really don't need to give any other argument than 0 to the drawArc instead of startRadians. Use the new offset to offset the start position and adjust the endRadians to where you want it to stop.
As you can see in the demo, using this technique keeps everything in check without the need to draw in split.
Tip: if you notice green artifacts on the edges: this is due to anti-alias. Simply reduce the line width for the green color by 2 pixels (see demo 2, off-screen canvas).