I drawn the svg circle using start and endangle as follow,
document.getElementById("circle").setAttribute("d", describeArc(150, 150, 100, 180, 360));
function getPathArc(center, start, end, radius) {
end = end - 0.0001;
var degree = end - start;
degree = degree < 0 ? (degree + 360) : degree;
var clockWise = (degree < 180) ? 0 : 1;
return getPiePath(center, degreeToLocation(start, radius, center), degreeToLocation(end, radius, center), radius, clockWise);
}
function getPiePath(center, start, end, radius, clockWise) {
return 'M ' + start.x + ' ' + start.y + ' A ' + radius + ' ' + radius + ' 0 ' + clockWise + ' 1 ' + end.x + ' ' + end.y;
};
function degreeToLocation(degree, radius, center) {
var radian = (degree * Math.PI) / 180;
return {
'x' : Math.cos(radian) * radius + center.x,
'y': Math.sin(radian) * radius + center.y
};
}
function describeArc(x, y, radius, startAngle, endAngle){
var endAngle = endAngle - startAngle;
startAngle = startAngle <= 0 ? (360 + startAngle) % 360 : startAngle % 360;
endAngle = endAngle < 0 ? (360 + endAngle + startAngle) % 360 : Math.abs(endAngle + startAngle) % 360;
var direction = getPathArc({'x': x, 'y': y}, startAngle, endAngle, radius);
var d = direction;
return d;
}
here is the sample https://jsfiddle.net/ndmsqmao/3/
i need to draw the one tick line for that circle for specified point.
for example let us consider,
if it's value is start from 50 to 100 mean i need to draw the one tick line for 66th value.. how to acheive this?
Hope this helps...
var minValue = 50, maxValue = 100, value = 66,
minAngle = 180, maxAngle = 360, angle;
angle = minAngle + (value - minValue) / (maxValue - minValue) * (maxAngle - minAngle);
alert(angle);
I hope i understand your Question...
var min = 50;
var max = 100;
var value = 66;
var angle = 180/(max-min)*(value-min)+180;
console.log (angle);
Related
I realize this is a simple Trigonometry question, but my high school is failing me right now.
Given an angle, that I have converted into radians to get the first point. How do I figure the next two points of the triangle to draw on the canvas, so as to make a small triangle always point outwards to the circle. So lets say Ive drawn a circle of a given radius already. Now I want a function to plot a triangle that sits on the edge of the circle inside of it, that points outwards no matter the angle. (follows the edge, so to speak)
function drawPointerTriangle(ctx, angle){
var radians = angle * (Math.PI/180)
var startX = this.radius + this.radius/1.34 * Math.cos(radians)
var startY = this.radius - this.radius/1.34 * Math.sin(radians)
// This gives me my starting point on the outer edge of the circle, plotted at the angle I need
ctx.moveTo(startX, startY);
// HOW DO I THEN CALCULATE x1,y1 and x2, y2. So that no matter what angle I enter into this function, the arrow/triangle always points outwards to the circle.
ctx.lineTo(x1, y1);
ctx.lineTo(x2, y2);
}
Example
You don't say what type of triangle you want to draw so I suppose that it is an equilateral triangle.
Take a look at this image (credit here)
I will call 3 points p1, p2, p3 from top right to bottom right, counterclockwise.
You can easily calculate the coordinate of three points of the triangle in the coordinate system with the origin is coincident with the triangle's centroid.
Given a point belongs to the edge of the circle and the point p1 that we just calculated, we can calculate parameters of the translation from our main coordinate system to the triangle's coordinate system. Then, we just have to translate the coordinate of two other points back to our main coordinate system. That is (x1,y1) and (x2,y2).
You can take a look at the demo below that is based on your code.
const w = 300;
const h = 300;
function calculateTrianglePoints(angle, width) {
let r = width / Math.sqrt(3);
let firstPoint = [
r * Math.cos(angle),
r * Math.sin(angle),
]
let secondPoint = [
r * Math.cos(angle + 2 * Math.PI / 3),
r * Math.sin(angle + 2 * Math.PI / 3),
]
let thirdPoint = [
r * Math.cos(angle + 4 * Math.PI / 3),
r * Math.sin(angle + 4 * Math.PI / 3),
]
return [firstPoint, secondPoint, thirdPoint]
}
const radius = 100
const triangleWidth = 20;
function drawPointerTriangle(ctx, angle) {
var radians = angle * (Math.PI / 180)
var startX = radius * Math.cos(radians)
var startY = radius * Math.sin(radians)
var [pt0, pt1, pt2] = calculateTrianglePoints(radians, triangleWidth);
var delta = [
startX - pt0[0],
startY - pt0[1],
]
pt1[0] = pt1[0] + delta[0]
pt1[1] = pt1[1] + delta[1]
pt2[0] = pt2[0] + delta[0]
pt2[1] = pt2[1] + delta[1]
ctx.beginPath();
// This gives me my starting point on the outer edge of the circle, plotted at the angle I need
ctx.moveTo(startX, startY);
[x1, y1] = pt1;
[x2, y2] = pt2;
// HOW DO I THEN CALCULATE x1,y1 and x2, y2. So that no matter what angle I enter into this function, the arrow/triangle always points outwards to the circle.
ctx.lineTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.closePath();
ctx.fillStyle = '#FF0000';
ctx.fill();
}
function drawCircle(ctx, radius) {
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.closePath();
ctx.fillStyle = '#000';
ctx.fill();
}
function clear(ctx) {
ctx.fillStyle = '#fff';
ctx.fillRect(-w / 2, -h / 2, w, h);
}
function normalizeAngle(pointCoordinate, angle) {
const [x, y] = pointCoordinate;
if (x > 0 && y > 0) return angle;
else if (x > 0 && y < 0) return 360 + angle;
else if (x < 0 && y < 0) return 180 - angle;
else if (x < 0 && y > 0) return 180 - angle;
}
function getAngleFromPoint(point) {
const [x, y] = point;
if (x == 0 && y == 0) return 0;
else if (x == 0) return 90 * (y > 0 ? 1 : -1);
else if (y == 0) return 180 * (x >= 0 ? 0: 1);
const radians = Math.asin(y / Math.sqrt(
x ** 2 + y ** 2
))
return normalizeAngle(point, radians / (Math.PI / 180))
}
document.addEventListener('DOMContentLoaded', function() {
const canvas = document.querySelector('canvas');
const angleText = document.querySelector('.angle');
const ctx = canvas.getContext('2d');
ctx.translate(w / 2, h / 2);
drawCircle(ctx, radius);
drawPointerTriangle(ctx, 0);
canvas.addEventListener('mousemove', _.throttle(function(ev) {
let mouseCoordinate = [
ev.clientX - w / 2,
ev.clientY - h / 2
]
let degAngle = getAngleFromPoint(mouseCoordinate)
clear(ctx);
drawCircle(ctx, radius);
drawPointerTriangle(ctx, degAngle)
angleText.innerText = Math.floor((360 - degAngle)*100)/100;
}, 15))
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
<canvas width=300 height=300></canvas>
<div class="angle">0</div>
reduce the radius, change the angle and call again cos/sin:
function drawPointerTriangle(ctx, angle)
{
var radians = angle * (Math.PI/180);
var radius = this.radius/1.34;
var startX = this.center.x + radius * Math.cos(radians);
var startY = this.center.y + radius * Math.sin(radians);
ctx.moveTo(startX, startY);
radius *= 0.9;
radians += 0.1;
var x1 = this.center.x + radius * Math.cos(radians);
var y1 = this.center.y + radius * Math.sin(radians);
radians -= 0.2;
var x1 = this.center.x + radius * Math.cos(radians);
var y1 = this.center.y + radius * Math.sin(radians);
ctx.lineTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.lineTo(startX, startY);
}
the resulting triangle's size is proportional to the size of the circle.
in case you need an equilateral, fixed size triangle, use this:
//get h by pythagoras
h = sqrt( a^2 - (a/2)^2 );)
//get phi using arcustangens:
phi = atan( a/2, radius-h );
//reduced radius h by pythagoras:
radius = sqrt( (radius-h)^2 + (a/2)^2 );
radians += phi;
...
radians -= 2*phi;
...
I have program where I click three times, each click creating a point on canvas. I then calculate angle between those three points like this:
function find_angle(A, B, C) {
var AB = Math.sqrt(Math.pow(B.x - A.x, 2) + Math.pow(B.y - A.y, 2));
var BC = Math.sqrt(Math.pow(B.x - C.x, 2) + Math.pow(B.y - C.y, 2));
var AC = Math.sqrt(Math.pow(C.x - A.x, 2) + Math.pow(C.y - A.y, 2));
return Math.acos((BC * BC + AB * AB - AC * AC) / (2 * BC * AB));
}
In example picture above, the calculated angle is 93°. I need to move point 3 by -3° so the points make exactly 90°. I have this function for it:
var angleToCorrect = alpha * (Math.PI / 180) - 90 * (Math.PI / 180);
correct_angle(point2, point3, angleToCorrect)
...
function correct_angle(p2, p3, angle) {
var x = p2.x - p3.x;
var y = p2.y - p3.y;
var r = Math.sqrt(x * x + y * y); //circle radius. origin of the circle is point 2
return {
X: p2.x + (Math.cos(angle) * r),
Y: p2.y + (Math.sin(angle) * r)
};
}
Now, this function should return new x and y for point 3 with corrected angle to 90°. Yet the coordinates don't agree with what I expect. Can someone point out what I'm doing wrong?
To calculate the new position it isn't enough to provide just two of the points since the angle is measured between the three.
So inside this function you have to figure out what the current angle of the vector between point 1 and point 2 is. Javascript offers a nifty built-in function for this Math.atan2()
Now that we know the angle (in radians) we need to add the new angle to it. This makes sure we can place point 3 correctly.
function correct_angle(p1, p2, p3, angle)
{
var currentAngle=Math.atan2(p1.y-p2.y, p1.x-p2.x);
currentAngle+=angle;
var x = p2.x - p3.x;
var y = p2.y - p3.y;
var r = Math.sqrt(x * x + y * y);
return {
X: p2.x + (Math.cos(currentAngle) * r),
Y: p2.y + (Math.sin(currentAngle) * r)
};
}
The angle parameter of the function should be the target angle in radians (90 or 1.5707963267949 in your case)
Here's an interactive example:
Point = function(x, y) {
this.x = x;
this.y = y;
}
var pointA = new Point(162, 39);
var pointB = new Point(105, 161);
var pointC = new Point(211, 242);
var context = document.getElementById("canvas").getContext("2d");
function correct() {
var newPoint = correct_angle(pointA, pointB, pointC, 1.5707963267949);
pointC.x = newPoint.X;
pointC.y = newPoint.Y;
draw();
}
function correct_angle(p1, p2, p3, angle) {
var currentAngle = Math.atan2(p1.y - p2.y, p1.x - p2.x);
currentAngle += angle;
var x = p2.x - p3.x;
var y = p2.y - p3.y;
var r = Math.sqrt(x * x + y * y);
return {
X: p2.x + (Math.cos(currentAngle) * r),
Y: p2.y + (Math.sin(currentAngle) * r)
};
}
function draw() {
context.clearRect(0, 0, 400, 300);
context.fillStyle = "red";
context.beginPath();
context.arc(pointA.x, pointA.y, 10, 0, 2 * Math.PI);
context.fill();
context.beginPath();
context.arc(pointB.x, pointB.y, 10, 0, 2 * Math.PI);
context.fill();
context.beginPath();
context.arc(pointC.x, pointC.y, 10, 0, 2 * Math.PI);
context.fill();
}
draw();
<canvas id="canvas" width="400" height="300" style="background-color:#dddddd;"></canvas>
<button onclick="correct()" style="float:left">
correct me
</button>
I'm trying to draw a spiral starting from a "start" point up to an "end point. The spiral also has a given center point so it can draw the spirals around that center point.
I can't make it work, somehow the math is totally wrong.
Any advice on how to solve this?
The jsfiddle of the code I tried is here.
<!DOCTYPE HTML>
<html>
<body>
<canvas id="myCanvas" width="800" height="600" style="border:1px solid #c3c3c3;"></canvas>
<script type="text/javascript">
var c = document.getElementById("myCanvas");
var cxt = c.getContext("2d");
//center of the spiral coords:
var centerX = 400;
var centerY = 300;
//draw the center of spiral point:
drawCirc(centerX, centerY, 10, '#6f0c4f');
var gap = 8;
var STEPS_PER_ROTATION = 50;
var rotations = 4;
var increment = rotations * Math.PI / STEPS_PER_ROTATION;
var theta = increment;
//start point:
var startX = 500;
var startY = 380;
//end point:
var endX = 600
var endY = 300;
//draw the start and end points as small circles:
drawCirc(startX, startY, 6, '#FF0000');
drawCirc(endX, endY, 6, '#00FF00');
//trying to calculate theta start position:
theta = Math.abs(((centerX - startX) / Math.cos(theta)) / gap);
var ind = 0;
while (theta < rotations * Math.PI * 2) {
var newX = centerX + theta * Math.cos(theta) * gap;
var newY = centerY + theta * Math.sin(theta) * gap;
var ukwObj = { x: newX, y: newY };
if (ind == 0) {
//draw start point with differnt color to differentiate
drawCirc(newX, newY, 2, 'orange');
} else {
drawCirc(newX, newY);
}
ind++;
theta = theta + increment;
}
function drawCirc(x, y, radius = 2, stroke = '#000000') {
cxt.beginPath();
cxt.arc(x, y, radius, 0, 2 * Math.PI);
cxt.strokeStyle = stroke;
cxt.stroke();
cxt.fillStyle = stroke;
cxt.fill();
}
cxt.stroke(); // draw the spiral
</script>
</body>
</html>
The principle of plotting a circle is:
Given a center x,y, a radius r, we can plot points belonging to the circle by calcultating their coordinates as follow: px = x + r * Math.cos(angle) and py = y + r * Math.sin(angle) when angle varies from 0 to 2* Math.PI.
If r grows when angle varies, the we get an outward spiral (from angle 0 to angle 2*PI which is equivalent to 0).
For the problem at hand we need to calculate a start and end position of the spiral, in polar coordinates (distance, angle).
So we need to compute the start angle, start distance, end angle and end distance, and plot each point by gradually incrementing both the angle and the distance.
The initial theta calculation was wrong, I've changed it.
Then I needed to calculate the start distance between center and start point, and the end distance between center and end point.
During rotation, you progressivley goes from start distance to end distance.
The total angle distance should be totalTheta = numberOfRotation * 2 * Math.PI + (endAngle - startAngle), I replaced rotations * Math.PI * 2 by totalTheta)
Just for fun and to demonstrate it works for any intial condition, I've randomized start position, end position and number of rotations slightly.
I've also decremented the angle increment at each iteration to make the distance between each point look more even, but you can comment to keep a constant angular speed.
The solution below will randomly choose an orange dot, a green dot, a number of turns to complete the spiral, and will plot the spiral around the fixed purple dot.
var c = document.getElementById("myCanvas");
var cxt = c.getContext("2d");
//center of the spiral coords:
var centerX = 200;
var centerY = 150;
//draw the center of spiral point:
drawCirc(centerX, centerY, 10, '#6f0c4f');
var gap = 8;
var STEPS_PER_ROTATION = 50;
var rotations = 1 + parseInt(Math.random() * 5, 10);
var increment = rotations * Math.PI / STEPS_PER_ROTATION;
var theta = increment;
var dist = 0;
//start point:
var startX = centerX + (Math.random() * 150 - 75);
var startY = centerY + (Math.random() * 150 - 75);
var startAngleOffset = startX > centerX ? (startY > centerY ? 0 : 0) : (startY > centerY ? Math.PI : Math.PI);
var startAngleSign = startX > centerX ? (startY > centerY ? 1 : -1) : (startY > centerY ? -1 : 1);
//end point:
var endX = centerX + (Math.random() * 150 - 75);
var endY = centerY + (Math.random() * 150 - 75);
var endAngleOffset = endX > centerX ? (endY > centerY ? 0 : 0) : (endY > centerY ? Math.PI : Math.PI);
var endAngleSign = endX > centerX ? (endY > centerY ? 1 : -1) : (endY > centerY ? -1 : 1);
//draw the start and end points as small circles:
drawCirc(startX, startY, 6, '#FF0000');
drawCirc(endX, endY, 6, '#00FF00');
var startTheta = theta = startAngleOffset + startAngleSign * Math.atan(Math.abs(startY - centerY)/Math.abs(startX - centerX));
var endTheta = endAngleOffset + endAngleSign * Math.atan(Math.abs(endY - centerY)/Math.abs(endX - centerX));
var totalTheta = rotations * 2 * Math.PI + (endTheta - startTheta)
dist = Math.sqrt(Math.pow(startY - centerY, 2) + Math.pow(startX - centerX, 2));
finalDist = Math.sqrt(Math.pow(endY - centerY, 2) + Math.pow(endX - centerX, 2));
var ind = 0;
while (theta -startTheta < totalTheta) {
var currentDist = (dist + ((finalDist - dist)* ((theta - startTheta) / (totalTheta))));
var newX = centerX + currentDist * Math.cos(theta);
var newY = centerY + currentDist * Math.sin(theta);
var ukwObj = { x: newX, y: newY };
if (ind == 0) {
//draw start point with differnt color to differentiate
drawCirc(newX, newY, 2, 'orange');
} else {
drawCirc(newX, newY);
}
ind++;
theta = theta + increment;
// decrement increment to make the space between points look more regular
increment = Math.max(0.01, increment - 0.00096);
}
function drawCirc(x, y, radius = 2, stroke = '#000000') {
cxt.beginPath();
cxt.arc(x, y, radius, 0, 2 * Math.PI);
cxt.strokeStyle = stroke;
cxt.stroke();
cxt.fillStyle = stroke;
cxt.fill();
}
cxt.stroke(); // draw the spiral
<!DOCTYPE HTML>
<html>
<body>
<canvas id="myCanvas" width="800" height="600" style="border:1px solid #c3c3c3;"></canvas>
</body>
</html>
I'm currently working on a Pinball game using the HTML5 Canvas and JavaScript. Right now I'm getting a hard time with the pixel by pixel collision, which is fundamental because of the flippers.
Right now my Bounding Box Collision seems to be working
checkCollision(element) {
if (this.checkCollisionBoundingBox(element)) {
console.log("colision with the element bounding box");
if (this.checkCollisionPixelByPixel(element)) {
return true;
} else {
return false;
}
} else {
return false;
}
}
checkCollisionBoundingBox(element) {
if (this.pos.x < element.pos.x + element.width && this.pos.x + this.width > element.pos.x && this.pos.y < element.pos.y + element.height && this.pos.y + this.height > element.pos.y) {
return true;
} else {
return false;
}
}
I've tried several ways of implementing the pixel by pixel one but for some reason it does not work perfectly (on walls, on images, on sprites etc). I'll leave them here:
checkCollisionPixelByPixel(element) {
var x_left = Math.floor(Math.max(this.pos.x, element.pos.x));
var x_right = Math.floor(Math.min(this.pos.x + this.width, element.pos.x + element.width));
var y_top = Math.floor(Math.max(this.pos.y, element.pos.y));
var y_bottom = Math.floor(Math.min(this.pos.y + this.height, element.pos.y + element.height));
for (var y = y_top; y < y_bottom; y++) {
for (var x = x_left; x < x_right; x++) {
var x_0 = Math.round(x - this.pos.x);
var y_0 = Math.round(y - this.pos.y);
var n_pix = y_0 * (this.width * this.total) + (this.width * (this.actual-1)) + x_0; //n pixel to check
var pix_op = this.imgData.data[4 * n_pix + 3]; //opacity (R G B A)
var element_x_0 = Math.round(x - element.pos.x);
var element_y_0 = Math.round(y - element.pos.y);
var element_n_pix = element_y_0 * (element.width * element.total) + (element.width * (element.actual-1)) + element_x_0; //n pixel to check
var element_pix_op = element.imgData.data[4 * element_n_pix + 3]; //opacity (R G B A)
console.log(element_pix_op);
if (pix_op == 255 && element_pix_op == 255) {
console.log("Colision pixel by pixel");
/*Debug*/
/*console.log("This -> (R:" + this.imgData.data[4 * n_pix] + ", G:" + this.imgData.data[4 * n_pix + 1] + ", B:" + this.imgData.data[4 * n_pix + 2] + ", A:" + pix_op + ")");
console.log("Element -> (R:" + element.imgData.data[4 * element_n_pix] + ", G:" + element.imgData.data[4 * element_n_pix + 1] + ", B:" + element.imgData.data[4 * element_n_pix + 2] + ", A:" + element_pix_op + ")");
console.log("Collision -> (x:" + x + ", y:" + y +")");
console.log("This(Local) -> (x:" + x_0 + ", y:" + y_0+")");
console.log("Element(Local) -> (x:" + element_x_0 + ", y:" + element_y_0+")");*/
/*ball vector*/
var vector = {
x: (x_0 - Math.floor(this.imgData.width / 2)),
y: -(y_0 - Math.floor(this.imgData.height / 2))
};
//console.log("ball vector -> ("+vector.x+", "+vector.y+") , Angulo: "+ Math.atan(vector.y/vector.x)* 180/Math.PI);
// THIS WAS THE FIRST TRY, IT DIDN'T WORK WHEN THE BALL WAS GOING NORTHEAST AND COLLIDED WITH A WALL. DIDN'T WORK AT ALL WITH SPRITES
//this.angle = (Math.atan2(vector.y, vector.x) - Math.PI) * (180 / Math.PI);
// THIS WAS THE SECOND ATTEMPT, WORKS WORSE THAN THE FIRST ONE :/
//normal vector
var normal = {
x: (x_0 - (this.imgData.width / 2)),
y: -(y_0 - (this.imgData.height / 2))
};
//Normalizar o vetor
var norm = Math.sqrt(normal.x * normal.x + normal.y * normal.y);
if (norm != 0) {
normal.x = normal.x / norm;
normal.y = normal.y / norm;
}
var n_rad = Math.atan2(normal.y, normal.x);
var n_deg = (n_rad + Math.PI) * 180 / Math.PI;
console.log("Vetor Normal -> (" + normal.x + ", " + normal.y + ") , Angulo: " + n_deg);
//Vetor Velocidade
var velocity = {
x: Math.cos((this.angle * Math.PI / 180) - Math.PI),
y: Math.sin((this.angle * Math.PI / 180) - Math.PI)
};
console.log("Vetor Velocidade -> (" + velocity.x + ", " + velocity.y + ") , Angulo: " + this.angle);
//Vetor Reflexao
var ndotv = normal.x * velocity.x + normal.y * velocity.y;
var reflection = {
x: -2 * ndotv * normal.x + velocity.x,
y: -2 * ndotv * normal.y + velocity.y
};
var r_rad = Math.atan2(reflection.y, reflection.x);
var r_deg = (r_rad + Math.PI) * 180 / Math.PI;
console.log("Vetor Reflexao -> (" + reflection.x + ", " + reflection.y + ") , Angulo: " + r_deg);
this.angle = r_deg;
return true;
}
}
}
return false;
}
}
The ball class
class Ball extends Element {
constructor(img, pos, width, height, n, sound, angle, speed) {
super(img, pos, width, height, n, sound);
this.angle = angle; //direction [0:360[
this.speed = speed;
}
move(ctx, cw, ch) {
var rads = this.angle * Math.PI / 180
var vx = Math.cos(rads) * this.speed / 60;
var vy = Math.sin(rads) * this.speed / 60;
this.pos.x += vx;
this.pos.y -= vy;
ctx.clearRect(0, 0, cw, ch);
this.draw(ctx, 1);
}
}
Assuming a "flipper" is composed of 2 arcs and 2 lines it would be much faster to do collision detection mathematically rather than by the much slower pixel-test method. Then you just need 4 math collision tests.
Even if your flippers are a bit more complicated than arcs+lines, the math hit tests would be "good enough" -- meaning in your fast-moving game, the user cannot visually notice the approximate math results vs the pixel-perfect results and the difference between the 2 types of tests will not affect gameplay at all. But the pixel-test version will take magnitudes more time and resources to accomplish. ;-)
First two circle-vs-circle collision tests:
function CirclesColliding(c1,c2){
var dx=c2.x-c1.x;
var dy=c2.y-c1.y;
var rSum=c1.r+c2.r;
return(dx*dx+dy*dy<=rSum*rSum);
}
Then two circle-vs-line-segment collision tests:
// [x0,y0] to [x1,y1] define a line segment
// [cx,cy] is circle centerpoint, cr is circle radius
function isCircleSegmentColliding(x0,y0,x1,y1,cx,cy,cr){
// calc delta distance: source point to line start
var dx=cx-x0;
var dy=cy-y0;
// calc delta distance: line start to end
var dxx=x1-x0;
var dyy=y1-y0;
// Calc position on line normalized between 0.00 & 1.00
// == dot product divided by delta line distances squared
var t=(dx*dxx+dy*dyy)/(dxx*dxx+dyy*dyy);
// calc nearest pt on line
var x=x0+dxx*t;
var y=y0+dyy*t;
// clamp results to being on the segment
if(t<0){x=x0;y=y0;}
if(t>1){x=x1;y=y1;}
return( (cx-x)*(cx-x)+(cy-y)*(cy-y) < cr*cr );
}
Found this on stack overflow the other day http://codepen.io/anon/pen/LERrGG.
I think this is a great pen that could be really useful. The only problem is that there is no ability to call a function after the timer runs out. I was trying to implement this with no success.
How do I edit the code so that it becomes a useful timer i.e. it 'runs out'?
(function animate() {
theta += 0.5;
theta %= 360;
var x = Math.sin(theta * Math.PI / 180) * radius;
var y = Math.cos(theta * Math.PI / 180) * -radius;
var d = 'M0,0 v' + -radius + 'A' + radius + ',' + radius + ' 1 ' + ((theta > 180) ? 1 : 0) + ',1 ' + x + ',' + y + 'z';
timer.setAttribute('d', d);
setTimeout(animate, t)
})();
You can determine that a complete circle has been painted by checking to see if theta ends up smaller than when it started out:
(function animate() {
var oldTheta = theta;
theta += 0.5;
theta %= 360;
if (theta < oldTheta) {
// the timer has "run out"
}
else {
var x = Math.sin(theta * Math.PI / 180) * radius;
var y = Math.cos(theta * Math.PI / 180) * -radius;
var d = 'M0,0 v' + -radius + 'A' + radius + ',' + radius + ' 1 ' + ((theta > 180) ? 1 : 0) + ',1 ' + x + ',' + y + 'z';
timer.setAttribute('d', d);
setTimeout(animate, t);
}
})();
you have to check if theta smaller than 360.
(function animate() {
theta += 0.5;
var x = Math.sin(theta * Math.PI / 180) * radius;
var y = Math.cos(theta * Math.PI / 180) * -radius;
var d = 'M0,0 v' + -radius + 'A' + radius + ',' + radius + ' 1 ' + ((theta > 180) ? 1 : 0) + ',1 ' + x + ',' + y + 'z';
timer.setAttribute('d', d);
if(theta<360) setTimeout(animate, t);
else doSomething();
})();