Canvas Elements avoid Center - javascript

I have been trying to get an array of circle to attract to the center of a canvas element but avoid a specific radius in middle. This gets them to move to the center thanks to this bit of code from codepen.io but I haven't been able to get them to avoid like a 300px radius in the middle. Any help is greatly appreciated.
// for each circle attraction to center
for (var i = 0; i < len; i++) {
var c0 = circles[i];
var dx = c0.x - canvas.center.x;
var dy = c0.y - canvas.center.y;
var f = 1 / c0.radius;
c0.x -= dx * 0.5 * f;
c0.y -= dy * 0.03;
}

You can do via following thing.
First, a function use to fill a circle.
var fillCircle = function(x, y, radius)
{
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fill();
};
clip()
var clearCircle = function(x, y, radius)
{
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.clip();
context.clearRect(x - radius - 1, y - radius - 1,
radius * 2 + 2, radius * 2 + 2);
};
See this jsFiddle.
globalCompositeOperation
var clearCircle = function(x, y, radius)
{
context.save();
context.globalCompositeOperation = 'destination-out';
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fill();
context.restore();
};
See this jsFiddle.
Both gave the desired result on screen.

Related

Rotating a line around a circle

I have two arcs with strokes and i want to have a line animate between them. The line should animate perpendicular to the points of the inner circle.
Here's something that I hacked together that is almost what I want.
things that are wrong with it are:
the length of the line is not the length between the 2 circle as it revolves around the inner circle.
sometimes the line is not perpendicular to the points of the inner circle. for example when it goes to the corner of the circle it tilts at an angle a little.
I had problem understanding how to use the trig function for lineTo. maybe because that changes the length of the line and I didn't know how to get the x and y coordinates of the outer circle to get the end point of the line. I'm used to doing math.cos * length and this gives me a line at an angle. I don't what a line I just wanted the coords of the outer circle.
window.onload = function(){
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
function lineAtAngle(startX, startY, angleDeg, length, startX2, startY2, angleDeg2, length2){
var angle = angleDeg * (Math.PI / 180);
var angle2 = angleDeg2 * (Math.PI / 180);
// context.moveTo(startX, startY);
context.beginPath();
context.moveTo(
Math.cos(angle) * length + startX,
Math.sin(angle) * length + startY
)
context.lineTo(
Math.cos(angle2) *(length2 )+ startX2,
Math.sin(angle2) *(length2) + startY2
)
// context.lineTo(canvas.width / 2 + 60, canvas.height / 2, angle2, length2)
context.lineWidth = 10;
context.stroke();
context.closePath();
console.log("startX2: " + startX2 + " startY2: " + startY2 )
console.log(Math.sin(angle2) + startY2)
console.log(length)
}
function myLineTo(startX, startY, angleDeg, length){
}
var length1 = canvas.width / 2 + 60 - canvas.width / 2 -30
var length2 = canvas.width / 2 ;
// var length2 = 1;
console.log(length2)
var angle1 = 0;
var angle2 = 0;
(function animate(){
context.clearRect(0,0, canvas.width, canvas.height);
window.requestAnimationFrame(animate);
context.beginPath()
context.arc(canvas.width / 2, canvas.height / 2, 30, 0, 2 * Math.PI, true)
context.lineWidth = 1;
context.stroke()
context.beginPath();
context.arc(canvas.width / 2, canvas.height / 2, 60, 0, 2 * Math.PI, true);
context.stroke();
context.closePath()
context.beginPath();
context.arc(canvas.width / 2, canvas.height / 2, 3, 0, 2 * Math.PI, true)
context.fill()
context.closePath();
angle1++
angle2++
// lineAtAngle(canvas.width / 2 , canvas.height / 2 , angle1, length1, canvas.width / 2 + 60, canvas.height / 2, angle2, length2 )
lineAtAngle(canvas.width / 2 , canvas.height / 2 , angle1, length1, canvas.width / 2 + 60, canvas.height / 2, angle2, length2 )
}())
}
canvas{
background: #aaa;
}
<canvas id="canvas" width="400" height="400"></canvas>
I believe the below is what you're trying to achieve.
I've simplified the code somewhat by using the Canvas's built-in methods to translate the coordinate space to the center and by removing the extra function which had way too many parameters passed when all it needed was one angle and two radii.
window.onload = function(){
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var radius1 = 30;
var radius2 = 60;
var angle = 0;
(function animate(){
context.clearRect(0, 0, canvas.width, canvas.height);
// save state and adjust coordinate space
context.save();
context.translate(canvas.width / 2, canvas.height / 2);
context.lineWidth = 1;
context.beginPath()
context.arc(0, 0, radius1, 0, 2 * Math.PI, true)
context.stroke()
context.beginPath();
context.arc(0, 0, radius2, 0, 2 * Math.PI, true);
context.stroke();
context.beginPath();
context.arc(0, 0, 3, 0, 2 * Math.PI, true);
context.fill()
++angle;
var rads = angle * Math.PI / 180;
var x = Math.cos(rads);
var y = Math.sin(rads);
context.lineWidth = 10;
context.beginPath();
context.moveTo(radius1 * x, radius1 * y);
context.lineTo(radius2 * x, radius2 * y);
context.stroke();
// restore transformations for next pass
context.restore();
window.requestAnimationFrame(animate)
}())
}
canvas { background: #aaa; }
<canvas id="canvas" width="400" height="200"></canvas>
The idea for drawing a line is that you need to supply a start point (moveTo), and an end point (lineTo). Your current code is complicating the whole thing with multiple angles and lengths. What you want to imagine you are doing is starting at the center of your circle, then adding an offset which places the start point at the edge of the inner circle. Using trig is perfectly fine here. The length of your line will simply be outer radius minus inner radius, in the same direction as your offset (only one angle was needed).
Without fundamentally changing your approach, the code below shows the changes you could use to try this. Have your line function take a starting point (x, y) and an offset, as well as the angle and length. The starting point is your circle center, and the offset is the radius of the inner circle. The length (again) is simply the outer radius minus the inner radius.
window.onload = function(){
var innerCircleRadius = 30;
var outerCircleRadius = 60;
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var angle1 = 0;
function lineAtAngle(startX, startY, angleDeg, offset, length) {
var angle = angleDeg * (Math.PI / 180); // Convert to radians.
var cosAngle = Math.cos(angle); // Only need cos(angle) once.
var sinAngle = Math.sin(angle); // Only need sin(angle) once.
var startXPos = cosAngle * offset + startX;
var startYPos = sinAngle * offset + startY;
var endXPos = cosAngle * length + startXPos;
var endYPos = sinAngle * length + startYPos;
context.beginPath();
context.moveTo(startXPos, startYPos);
context.lineTo(endXPos, endYPos);
context.lineWidth = 10;
context.stroke();
context.closePath();
}
(function animate() {
context.clearRect(0,0, canvas.width, canvas.height);
window.requestAnimationFrame(animate);
context.beginPath()
context.arc(canvas.width / 2, canvas.height / 2, innerCircleRadius, 0, 2 * Math.PI, true)
context.lineWidth = 1;
context.stroke()
context.beginPath();
context.arc(canvas.width / 2, canvas.height / 2, outerCircleRadius, 0, 2 * Math.PI, true);
context.stroke();
context.closePath()
context.beginPath();
context.arc(canvas.width / 2, canvas.height / 2, 3, 0, 2 * Math.PI, true)
context.fill()
context.closePath();
angle1++
lineAtAngle(canvas.width / 2 , canvas.height / 2 , angle1, innerCircleRadius, outerCircleRadius - innerCircleRadius);
}())
}
canvas {
background: #aaa;
}
<canvas id="canvas" width="400" height="400"></canvas>

how to fill certain percentage area of circle in color in html canvas?

I have some 9 circles in my html page.Each circle has to be filled with certain color with certain percentage.I have drawn the circles using html5 canvas element.But i was only able to fill the enitre circle with a color and not certain percantage area.How can i achieve that?
"Fuel tank", filling of circle
Use composite mode:
Use the radius x2 for height (or width)
Draw and fill the complete circle
Use composite mode destination-out
Draw a filled rectangle on top representing the % of the height
The main code would be:
var o = radius * 2, // diameter => width and height of rect
h = o - (o * percent / 100); // height based on percentage
ctx.beginPath();
ctx.arc(x, y, radius, 0, 6.28);
ctx.fill();
ctx.globalCompositeOperation = "destination-out";
ctx.fillRect(x - radius, y - radius, o, h); // this will remove a part of the top
Demo
var ctx = document.querySelector("canvas").getContext("2d"),
pst = 0, dlt = 2;
ctx.fillStyle = "#28f";
function drawCircle(ctx, x, y, radius, percent) {
var o = radius * 2,
h = o - (o * percent / 100);
ctx.globalCompositeOperation = "source-over"; // make sure we have default mode
ctx.beginPath(); // fill an arc
ctx.arc(x, y, radius, 0, 6.28);
ctx.fill();
ctx.globalCompositeOperation = "destination-out"; // mode to use for next op.
ctx.fillRect(x - radius, y - radius, o, h); // "clear" part of arc
ctx.globalCompositeOperation = "source-over"; // be polite, set default mode back
}
(function loop() {
ctx.clearRect(0,0,300,150);
drawCircle(ctx, 70, 70, 60, pst);
pst += dlt;
if (pst <= 0 || pst >= 100) dlt = -dlt;
requestAnimationFrame(loop);
})();
<canvas></canvas>
Pie type
Move to center of circle
Add arc, this will create a line from center to start of arc
Close path, this will create a line from end of arc back to center, and fill
(tip: closePath() is really not necessary with fill() as fill() will close the path implicit, but it's needed if you want to do a stroke() instead).
The essential part being:
ctx.beginPath();
ctx.moveTo(x, y);
ctx.arc(x, y, radius, 0, 2 * Math.PI * percent / 100);
//ctx.closePath(); // for stroke, not needed for fill
ctx.fill();
Demo
var ctx = document.querySelector("canvas").getContext("2d"),
pst = 0, dlt = 2;
ctx.fillStyle = "#28f";
function drawPie(ctx, x, y, radius, percent) {
ctx.beginPath();
ctx.moveTo(x, y);
ctx.arc(x, y, radius, 0, 2 * Math.PI * percent /100);
ctx.fill();
}
(function loop() {
ctx.clearRect(0,0,300,150); drawPie(ctx, 70, 70, 60, pst);
pst += dlt; if (pst <= 0 || pst >= 100) dlt = -dlt;
requestAnimationFrame(loop);
})();
<canvas></canvas>
Outlined circle:
Almost same as with pie type, but with these changes:
Move to outer edge of arc at angle 0 (or the angle you want to start from)
Add arc to path
Stroke (remember to set lineWidth, see demo below)
Essential part:
ctx.beginPath();
ctx.moveTo(x + radius, y); // cos(0) for x = 1, so just use radius, sin(0) = 0
ctx.arc(x, y, radius, 0, 2 * Math.PI * percent /100);
ctx.stroke();
You can adjust gap point using rotation transform or calculating the actual point using trigonometry.
Demo
var ctx = document.querySelector("canvas").getContext("2d"),
pst = 0, dlt = 2;
ctx.strokeStyle = "#28f";
ctx.lineWidth = 8;
function drawWedge(ctx, x, y, radius, percent) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.arc(x, y, radius, 0, 2 * Math.PI * percent /100);
ctx.stroke();
}
(function loop() {
ctx.clearRect(0,0,300,150); drawWedge(ctx, 70, 70, 60, pst);
pst += dlt; if (pst <= 0 || pst >= 100) dlt = -dlt;
requestAnimationFrame(loop);
})();
<canvas></canvas>
Using different starting point
You can change the starting point for the arc using rotation transform or calculating the point manually using trigonometry.
To calculate these manually you can do (angles in radians):
x = radius * Math.cos(angleInRad); // end point for x
y = radius * Math.sin(angleInRad); // end point for y
Just add the total angle to the start angle to get end point.
360° in radians = 2 x PI, so if you want to use angles in degrees, convert them using:
angleInRad = angleInDeg * Math.PI / 180;
Demo, rotated using transfrom and counter-clock-wise mode
var ctx = document.querySelector("canvas").getContext("2d"),
pst = 0, dlt = 2;
ctx.strokeStyle = "#28f";
ctx.lineWidth = 8;
function drawWedge(ctx, x, y, radius, percent) {
ctx.translate(x, y); // translate to rotating pivot
ctx.rotate(Math.PI * 0.5); // rotate, here 90° deg
ctx.translate(-x, -y); // translate back
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.arc(x, y, radius, 0, 2 * Math.PI * percent /100);
ctx.stroke();
ctx.setTransform(1,0,0,1,0,0); // reset transform
}
(function loop() {
ctx.clearRect(0,0,300,150); drawWedge(ctx, 70, 70, 60, pst);
pst += dlt; if (pst <= 0 || pst >= 100) dlt = -dlt;
requestAnimationFrame(loop);
})();
<canvas></canvas>

Trying to get my dot-to-dot game to 'snap to' the closest dot

I know it's a simple calculation, but can you help me?
Here's the fiddle.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var radius = 4;
for (x=radius; x<canvas.width-radius; x+=50) {
for (y=radius; y<canvas.height-radius; y+=50) {
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.stroke();
}
}
$('canvas').click(canvasClicked);
function canvasClicked(e) {
var x = e.pageX - $(this).offset().left;
var y = e.pageY - $(this).offset().top;
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'black';
context.fill();
context.lineWidth = 1;
context.strokeStyle = '#000000';
context.stroke();
};
I'm trying to identify which cirlce is the one that's closest to where the user clicked.
The answer is here:
var newX = Math.round(x/50)*50 + radius;
var newY = Math.round(y/50)*50 + radius;
x = newX;
y = newY;
Here's the fiddle for that:
http://jsfiddle.net/avall/vtEER/1/
You round the clicked position to the resolution of your dot generator;
Oh, and you should watch out for edge points - didn't do ifs for that

How can I bisect the circle?

I'm trying to bisect a circle with JavaScript and a <canvas> element. I used the formula given in the accepted answer to this question to find points on the edge of the circle, but for some reason when I give two opposite points on the circle (0 and 180, or 90 and 270, for example) I'm not getting a line that goes through the center of the circle.
My code, which you can see on JSFiddle, makes a nice Spirograph pattern, which is cool except that that's not what I'm trying to do.
How do I fix this so the lines go through the center?
(Ultimately I'm trying to draw a circle of fifths, but all I'm asking how to do now is get the lines to go through the center. Once that works I'll get on with the other steps to do the circle of fifths, which will obviously include drawing fewer lines and losing the Spirograph torus.)
Degrees in Javascript are specified in radians. Instead of checking for greater than or less than 180, and adding or subtracting 180, do the same with Math.PI radians.
http://jsfiddle.net/7w29h/1/
Drawing function and trigonometry function in Math expects angle to be specified in radian, not degree.
Demo
Diff with your current code:
function bisect(context, degrees, radius, cx, cy) {
// calculate the point on the edge of the circle
var x1 = cx + radius * Math.cos(degrees / 180 * Math.PI);
var y1 = cy + radius * Math.sin(degrees / 180 * Math.PI);
/* Trimmed */
// and calculate the point on the opposite side
var x2 = cx + radius * Math.cos(degrees2 / 180 * Math.PI);
var y2 = cy + radius * Math.sin(degrees2 / 180 * Math.PI);
/* Trimmed */
}
function draw(theCanvas) {
/* Trimmed */
// 2 * PI, which is 360 degree
context.arc(250, 250, 220, 0, Math.PI * 2, false);
/* Trimmed */
context.arc(250, 250, 110, 0, Math.PI * 2, false);
/* Trimmed */
// No need to go up to 360 degree, unless the increment does
// not divides 180
for (j = 2; j < 180; j = j + 3) {
bisect(context, j, 220, 250, 250);
}
/* Trimmed */
}
Appendix
This is the full source code from JSFiddle, keep the full copy here just in case.
HTML
<canvas id="the_canvas" width="500" height="500"></canvas>
CSS
canvas {
border:1px solid black;
}
JavaScript
function bisect(context, degrees, radius, cx, cy) {
// calculate the point on the edge of the circle
var x1 = cx + radius * Math.cos(degrees / 180 * Math.PI);
var y1 = cy + radius * Math.sin(degrees / 180 * Math.PI);
// get the point on the opposite side of the circle
// e.g. if 90, get 270, and vice versa
// (super verbose but easily readable)
if (degrees > 180) {
var degrees2 = degrees - 180;
} else {
var degrees2 = degrees + 180;
}
// and calculate the point on the opposite side
var x2 = cx + radius * Math.cos(degrees2 / 180 * Math.PI);
var y2 = cy + radius * Math.sin(degrees2 / 180 * Math.PI);
// now actually draw the line
context.beginPath();
context.moveTo(x1, y1)
context.lineTo(x2, y2)
context.stroke();
}
function draw(theCanvas) {
var context = theCanvas.getContext('2d');
// draw the big outer circle
context.beginPath();
context.strokeStyle = "#222222";
context.lineWidth = 2;
context.arc(250, 250, 220, 0, Math.PI * 2, false);
context.stroke();
context.closePath();
// smaller inner circle
context.beginPath();
context.strokeStyle = "#222222";
context.lineWidth = 1;
context.arc(250, 250, 110, 0, Math.PI * 2, false);
context.stroke();
context.closePath();
for (j=2; j < 180; j = j + 3) {
bisect(context, j, 220, 250, 250);
}
}
$(function () {
var theCanvas = document.getElementById('the_canvas');
console.log(theCanvas);
draw(theCanvas, 50, 0, 270);
});

How to make the text write in counterclockwise direction

How do I make text write counter-clockwise?
function drawTextAlongArc(context, str, centerX, centerY, radius, angle){
context.save();
context.translate(centerX, centerY);
context.rotate(-1 * angle / 2);
context.rotate(-1 * (angle / str.length) / 2);
for (var n = 0; n < str.length; n++) {
context.rotate(angle / str.length);
context.save();
context.translate(0, -1 * radius);
var char = str[n];
context.fillText(char, 0, 0);
context.restore();
}
context.restore();
}
window.onload = function(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.font = "30pt Calibri";
context.textAlign = "center";
context.fillStyle = "blue";
context.strokeStyle = "blue";
context.lineWidth = 4;
var centerX = canvas.width / 2;
var centerY = canvas.height - 30;
var angle = Math.PI * 0.8; // radians
var radius = 150;
drawTextAlongArc(context, "Text along arc path", centerX, centerY, radius, angle);
// draw circle underneath text
context.arc(centerX, centerY, radius - 10, 0, 2 * Math.PI, false);
context.stroke();
};
I want to text to appear like this in counter clockwise
Not sure what you're asking, but if you want to write your text backwards in a counter-clockwise direction you'd just change this line:
drawTextAlongArc(context, "Text along arc path", centerX, centerY, radius, -angle);
last argument changed to -angle
the text is going to be backwards though, as you would expect.

Categories