Canvas with same id in html - javascript
I have in Ui and I dont know how to solve it.
I Use canvas in my project and base on id it choose what should be happen
Hear is my cod:
<div class="item">
<div class="w3_weather_scroll">
<h4>3:00 PM</h4>
<h5>-5°</h5>
<canvas id="rain" width="30" name="name" height="30"></canvas>
</div>
</div>
<div class="item">
<div class="w3_weather_scroll">
<h4>5:00 PM</h4>
<h5>35°</h5>
<canvas id="wind" width="30" name="name" height="30"></canvas>
</div>
java script:
var icons = new Skycons({"color": "#fff"}),
list = [
document.getElementsByName("name")[0].id,
document.getElementsByName("name")[1].className,
document.getElementsByName("name")[2].id,
document.getElementsByName("name")[3].id,
document.getElementsByName("name")[4].id,
document.getElementsByName("name")[5].id,
document.getElementsByName("name")[6].id,
document.getElementsByName("name")[7].id,
],
i;
document.getElementById("demo").innerHTML=document.getElementsByName("name")[0].id;
for(i = list.length; i--; )
icons.set(list[i], list[i]);
icons.play();
for example if first id is "rain" and second id is"wind" , for first one we have rainy cloud img and second wind .
(function(global) {
"use strict";
/* Set up a RequestAnimationFrame shim so we can animate efficiently FOR
* GREAT JUSTICE. */
var requestInterval, cancelInterval;
(function() {
var raf = global.requestAnimationFrame ||
global.webkitRequestAnimationFrame ||
global.mozRequestAnimationFrame ||
global.oRequestAnimationFrame ||
global.msRequestAnimationFrame ,
caf = global.cancelAnimationFrame ||
global.webkitCancelAnimationFrame ||
global.mozCancelAnimationFrame ||
global.oCancelAnimationFrame ||
global.msCancelAnimationFrame ;
if(raf && caf) {
requestInterval = function(fn, delay) {
var handle = {value: null};
function loop() {
handle.value = raf(loop);
fn();
}
loop();
return handle;
};
cancelInterval = function(handle) {
caf(handle.value);
};
}
else {
requestInterval = setInterval;
cancelInterval = clearInterval;
}
}());
/* Define skycon things. */
/* FIXME: I'm *really really* sorry that this code is so gross. Really, I am.
* I'll try to clean it up eventually! Promise! */
var KEYFRAME = 500,
STROKE = 0.08,
TAU = 2.0 * Math.PI,
TWO_OVER_SQRT_2 = 2.0 / Math.sqrt(2);
function circle(ctx, x, y, r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, TAU, false);
ctx.fill();
}
function line(ctx, ax, ay, bx, by) {
ctx.beginPath();
ctx.moveTo(ax, ay);
ctx.lineTo(bx, by);
ctx.stroke();
}
function puff(ctx, t, cx, cy, rx, ry, rmin, rmax) {
var c = Math.cos(t * TAU),
s = Math.sin(t * TAU);
rmax -= rmin;
circle(
ctx,
cx - s * rx,
cy + c * ry + rmax * 0.5,
rmin + (1 - c * 0.5) * rmax
);
}
function puffs(ctx, t, cx, cy, rx, ry, rmin, rmax) {
var i;
for(i = 5; i--; )
puff(ctx, t + i / 5, cx, cy, rx, ry, rmin, rmax);
}
function cloud(ctx, t, cx, cy, cw, s, color) {
t /= 30000;
var a = cw * 0.21,
b = cw * 0.12,
c = cw * 0.24,
d = cw * 0.28;
ctx.fillStyle = color;
puffs(ctx, t, cx, cy, a, b, c, d);
ctx.globalCompositeOperation = 'destination-out';
puffs(ctx, t, cx, cy, a, b, c - s, d - s);
ctx.globalCompositeOperation = 'source-over';
}
function sun(ctx, t, cx, cy, cw, s, color) {
t /= 40000;
var a = cw * 0.25 - s * 0.5,
b = cw * 0.32 + s * 0.5,
c = cw * 0.50 - s * 0.5,
i, p, cos, sin;
ctx.strokeStyle = color;
ctx.lineWidth = s;
ctx.lineCap = "round";
ctx.lineJoin = "round";
ctx.beginPath();
ctx.arc(cx, cy, a, 0, TAU, false);
ctx.stroke();
for(i = 8; i--; ) {
p = (t + i / 8) * TAU;
cos = Math.cos(p);
sin = Math.sin(p);
line(ctx, cx + cos * b, cy + sin * b, cx + cos * c, cy + sin * c);
}
}
function moon(ctx, t, cx, cy, cw, s, color) {
t /= 15000;
var a = cw * 0.29 - s * 0.5,
b = cw * 0.05,
c = Math.cos(t * TAU),
p = c * TAU / -16;
ctx.strokeStyle = color;
ctx.lineWidth = s;
ctx.lineCap = "round";
ctx.lineJoin = "round";
cx += c * b;
ctx.beginPath();
ctx.arc(cx, cy, a, p + TAU / 8, p + TAU * 7 / 8, false);
ctx.arc(cx + Math.cos(p) * a * TWO_OVER_SQRT_2, cy + Math.sin(p) * a * TWO_OVER_SQRT_2, a, p + TAU * 5 / 8, p + TAU * 3 / 8, true);
ctx.closePath();
ctx.stroke();
}
function rain(ctx, t, cx, cy, cw, s, color) {
t /= 1350;
var a = cw * 0.16,
b = TAU * 11 / 12,
c = TAU * 7 / 12,
i, p, x, y;
ctx.fillStyle = color;
for(i = 4; i--; ) {
p = (t + i / 4) % 1;
x = cx + ((i - 1.5) / 1.5) * (i === 1 || i === 2 ? -1 : 1) * a;
y = cy + p * p * cw;
ctx.beginPath();
ctx.moveTo(x, y - s * 1.5);
ctx.arc(x, y, s * 0.75, b, c, false);
ctx.fill();
}
}
function sleet(ctx, t, cx, cy, cw, s, color) {
t /= 750;
var a = cw * 0.1875,
b = TAU * 11 / 12,
c = TAU * 7 / 12,
i, p, x, y;
ctx.strokeStyle = color;
ctx.lineWidth = s * 0.5;
ctx.lineCap = "round";
ctx.lineJoin = "round";
for(i = 4; i--; ) {
p = (t + i / 4) % 1;
x = Math.floor(cx + ((i - 1.5) / 1.5) * (i === 1 || i === 2 ? -1 : 1) * a) + 0.5;
y = cy + p * cw;
line(ctx, x, y - s * 1.5, x, y + s * 1.5);
}
}
function snow(ctx, t, cx, cy, cw, s, color) {
t /= 3000;
var a = cw * 0.16,
b = s * 0.75,
u = t * TAU * 0.7,
ux = Math.cos(u) * b,
uy = Math.sin(u) * b,
v = u + TAU / 3,
vx = Math.cos(v) * b,
vy = Math.sin(v) * b,
w = u + TAU * 2 / 3,
wx = Math.cos(w) * b,
wy = Math.sin(w) * b,
i, p, x, y;
ctx.strokeStyle = color;
ctx.lineWidth = s * 0.5;
ctx.lineCap = "round";
ctx.lineJoin = "round";
for(i = 4; i--; ) {
p = (t + i / 4) % 1;
x = cx + Math.sin((p + i / 4) * TAU) * a;
y = cy + p * cw;
line(ctx, x - ux, y - uy, x + ux, y + uy);
line(ctx, x - vx, y - vy, x + vx, y + vy);
line(ctx, x - wx, y - wy, x + wx, y + wy);
}
}
function fogbank(ctx, t, cx, cy, cw, s, color) {
t /= 30000;
var a = cw * 0.21,
b = cw * 0.06,
c = cw * 0.21,
d = cw * 0.28;
ctx.fillStyle = color;
puffs(ctx, t, cx, cy, a, b, c, d);
ctx.globalCompositeOperation = 'destination-out';
puffs(ctx, t, cx, cy, a, b, c - s, d - s);
ctx.globalCompositeOperation = 'source-over';
}
/*
var WIND_PATHS = [
downsample(63, upsample(8, [
-1.00, -0.28,
-0.75, -0.18,
-0.50, 0.12,
-0.20, 0.12,
-0.04, -0.04,
-0.07, -0.18,
-0.19, -0.18,
-0.23, -0.05,
-0.12, 0.11,
0.02, 0.16,
0.20, 0.15,
0.50, 0.07,
0.75, 0.18,
1.00, 0.28
])),
downsample(31, upsample(16, [
-1.00, -0.10,
-0.75, 0.00,
-0.50, 0.10,
-0.25, 0.14,
0.00, 0.10,
0.25, 0.00,
0.50, -0.10,
0.75, -0.14,
1.00, -0.10
]))
];
*/
var WIND_PATHS = [
[
-0.7500, -0.1800, -0.7219, -0.1527, -0.6971, -0.1225,
-0.6739, -0.0910, -0.6516, -0.0588, -0.6298, -0.0262,
-0.6083, 0.0065, -0.5868, 0.0396, -0.5643, 0.0731,
-0.5372, 0.1041, -0.5033, 0.1259, -0.4662, 0.1406,
-0.4275, 0.1493, -0.3881, 0.1530, -0.3487, 0.1526,
-0.3095, 0.1488, -0.2708, 0.1421, -0.2319, 0.1342,
-0.1943, 0.1217, -0.1600, 0.1025, -0.1290, 0.0785,
-0.1012, 0.0509, -0.0764, 0.0206, -0.0547, -0.0120,
-0.0378, -0.0472, -0.0324, -0.0857, -0.0389, -0.1241,
-0.0546, -0.1599, -0.0814, -0.1876, -0.1193, -0.1964,
-0.1582, -0.1935, -0.1931, -0.1769, -0.2157, -0.1453,
-0.2290, -0.1085, -0.2327, -0.0697, -0.2240, -0.0317,
-0.2064, 0.0033, -0.1853, 0.0362, -0.1613, 0.0672,
-0.1350, 0.0961, -0.1051, 0.1213, -0.0706, 0.1397,
-0.0332, 0.1512, 0.0053, 0.1580, 0.0442, 0.1624,
0.0833, 0.1636, 0.1224, 0.1615, 0.1613, 0.1565,
0.1999, 0.1500, 0.2378, 0.1402, 0.2749, 0.1279,
0.3118, 0.1147, 0.3487, 0.1015, 0.3858, 0.0892,
0.4236, 0.0787, 0.4621, 0.0715, 0.5012, 0.0702,
0.5398, 0.0766, 0.5768, 0.0890, 0.6123, 0.1055,
0.6466, 0.1244, 0.6805, 0.1440, 0.7147, 0.1630,
0.7500, 0.1800
],
[
-0.7500, 0.0000, -0.7033, 0.0195, -0.6569, 0.0399,
-0.6104, 0.0600, -0.5634, 0.0789, -0.5155, 0.0954,
-0.4667, 0.1089, -0.4174, 0.1206, -0.3676, 0.1299,
-0.3174, 0.1365, -0.2669, 0.1398, -0.2162, 0.1391,
-0.1658, 0.1347, -0.1157, 0.1271, -0.0661, 0.1169,
-0.0170, 0.1046, 0.0316, 0.0903, 0.0791, 0.0728,
0.1259, 0.0534, 0.1723, 0.0331, 0.2188, 0.0129,
0.2656, -0.0064, 0.3122, -0.0263, 0.3586, -0.0466,
0.4052, -0.0665, 0.4525, -0.0847, 0.5007, -0.1002,
0.5497, -0.1130, 0.5991, -0.1240, 0.6491, -0.1325,
0.6994, -0.1380, 0.7500, -0.1400
]
],
WIND_OFFSETS = [
{start: 0.36, end: 0.11},
{start: 0.56, end: 0.16}
];
function leaf(ctx, t, x, y, cw, s, color) {
var a = cw / 8,
b = a / 3,
c = 2 * b,
d = (t % 1) * TAU,
e = Math.cos(d),
f = Math.sin(d);
ctx.fillStyle = color;
ctx.strokeStyle = color;
ctx.lineWidth = s;
ctx.lineCap = "round";
ctx.lineJoin = "round";
ctx.beginPath();
ctx.arc(x , y , a, d , d + Math.PI, false);
ctx.arc(x - b * e, y - b * f, c, d + Math.PI, d , false);
ctx.arc(x + c * e, y + c * f, b, d + Math.PI, d , true );
ctx.globalCompositeOperation = 'destination-out';
ctx.fill();
ctx.globalCompositeOperation = 'source-over';
ctx.stroke();
}
function swoosh(ctx, t, cx, cy, cw, s, index, total, color) {
t /= 2500;
var path = WIND_PATHS[index],
a = (t + index - WIND_OFFSETS[index].start) % total,
c = (t + index - WIND_OFFSETS[index].end ) % total,
e = (t + index ) % total,
b, d, f, i;
ctx.strokeStyle = color;
ctx.lineWidth = s;
ctx.lineCap = "round";
ctx.lineJoin = "round";
if(a < 1) {
ctx.beginPath();
a *= path.length / 2 - 1;
b = Math.floor(a);
a -= b;
b *= 2;
b += 2;
ctx.moveTo(
cx + (path[b - 2] * (1 - a) + path[b ] * a) * cw,
cy + (path[b - 1] * (1 - a) + path[b + 1] * a) * cw
);
if(c < 1) {
c *= path.length / 2 - 1;
d = Math.floor(c);
c -= d;
d *= 2;
d += 2;
for(i = b; i !== d; i += 2)
ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw);
ctx.lineTo(
cx + (path[d - 2] * (1 - c) + path[d ] * c) * cw,
cy + (path[d - 1] * (1 - c) + path[d + 1] * c) * cw
);
}
else
for(i = b; i !== path.length; i += 2)
ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw);
ctx.stroke();
}
else if(c < 1) {
ctx.beginPath();
c *= path.length / 2 - 1;
d = Math.floor(c);
c -= d;
d *= 2;
d += 2;
ctx.moveTo(cx + path[0] * cw, cy + path[1] * cw);
for(i = 2; i !== d; i += 2)
ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw);
ctx.lineTo(
cx + (path[d - 2] * (1 - c) + path[d ] * c) * cw,
cy + (path[d - 1] * (1 - c) + path[d + 1] * c) * cw
);
ctx.stroke();
}
if(e < 1) {
e *= path.length / 2 - 1;
f = Math.floor(e);
e -= f;
f *= 2;
f += 2;
leaf(
ctx,
t,
cx + (path[f - 2] * (1 - e) + path[f ] * e) * cw,
cy + (path[f - 1] * (1 - e) + path[f + 1] * e) * cw,
cw,
s,
color
);
}
}
var Skycons = function(opts) {
this.list = [];
this.interval = null;
this.color = opts && opts.color ? opts.color : "black";
this.resizeClear = !!(opts && opts.resizeClear);
};
Skycons.CLEAR_DAY = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
sun(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color);
};
Skycons.CLEAR_NIGHT = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
moon(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color);
};
Skycons.PARTLY_CLOUDY_DAY = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
sun(ctx, t, w * 0.625, h * 0.375, s * 0.75, s * STROKE, color);
cloud(ctx, t, w * 0.375, h * 0.625, s * 0.75, s * STROKE, color);
};
Skycons.PARTLY_CLOUDY_NIGHT = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
moon(ctx, t, w * 0.667, h * 0.375, s * 0.75, s * STROKE, color);
cloud(ctx, t, w * 0.375, h * 0.625, s * 0.75, s * STROKE, color);
};
Skycons.CLOUDY = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
cloud(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color);
};
Skycons.RAIN = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
rain(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color);
cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color);
};
Skycons.SLEET = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
sleet(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color);
cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color);
};
Skycons.SNOW = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
snow(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color);
cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color);
};
Skycons.WIND = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
swoosh(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, 0, 2, color);
swoosh(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, 1, 2, color);
};
Skycons.FOG = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h),
k = s * STROKE;
fogbank(ctx, t, w * 0.5, h * 0.32, s * 0.75, k, color);
t /= 5000;
var a = Math.cos((t ) * TAU) * s * 0.02,
b = Math.cos((t + 0.25) * TAU) * s * 0.02,
c = Math.cos((t + 0.50) * TAU) * s * 0.02,
d = Math.cos((t + 0.75) * TAU) * s * 0.02,
n = h * 0.936,
e = Math.floor(n - k * 0.5) + 0.5,
f = Math.floor(n - k * 2.5) + 0.5;
ctx.strokeStyle = color;
ctx.lineWidth = k;
ctx.lineCap = "round";
ctx.lineJoin = "round";
line(ctx, a + w * 0.2 + k * 0.5, e, b + w * 0.8 - k * 0.5, e);
line(ctx, c + w * 0.2 + k * 0.5, f, d + w * 0.8 - k * 0.5, f);
};
Skycons.prototype = {
_determineDrawingFunction: function(draw) {
if(typeof draw === "string")
draw = Skycons[draw.toUpperCase().replace(/-/g, "_")] || null;
return draw;
},
add: function(el, draw) {
var obj;
if(typeof el === "string")
el = document.getElementById(el);
// Does nothing if canvas name doesn't exists
if(el === null)
return;
draw = this._determineDrawingFunction(draw);
// Does nothing if the draw function isn't actually a function
if(typeof draw !== "function")
return;
obj = {
element: el,
context: el.getContext("2d"),
drawing: draw
};
this.list.push(obj);
this.draw(obj, KEYFRAME);
},
set: function(el, draw) {
var i;
if(typeof el === "string")
el = document.getElementById(el);
for(i = this.list.length; i--; )
if(this.list[i].element === el) {
this.list[i].drawing = this._determineDrawingFunction(draw);
this.draw(this.list[i], KEYFRAME);
return;
}
this.add(el, draw);
},
remove: function(el) {
var i;
if(typeof el === "string")
el = document.getElementById(el);
for(i = this.list.length; i--; )
if(this.list[i].element === el) {
this.list.splice(i, 1);
return;
}
},
draw: function(obj, time) {
var canvas = obj.context.canvas;
if(this.resizeClear)
canvas.width = canvas.width;
else
obj.context.clearRect(0, 0, canvas.width, canvas.height);
obj.drawing(obj.context, time, this.color);
},
play: function() {
var self = this;
this.pause();
this.interval = requestInterval(function() {
var now = Date.now(),
i;
for(i = self.list.length; i--; )
self.draw(self.list[i], now);
}, 1000 / 60);
},
pause: function() {
var i;
if(this.interval) {
cancelInterval(this.interval);
this.interval = null;
}
}
};
global.Skycons = Skycons;
}(this));
hear is jascript:
But if both of them is rain it just show rain img for first one .
In HTML, id must be unique, so you can only target the first occurrence of a given id.
You should use a class instead to target multiple elements with the same class, using document.getElementsByClassName("rain").
We can not help you more without your Javascript code.
Related
How to calculate all pixels on the circumference of an ellipse?
I am drawing an ellipse in a "canvas" element with the following lines of code: let centerX = 250, centerY = 250; let widthEllipse = 75; let heightEllipse = 50; context.beginPath(); context.lineWidth = 1; context.ellipse(centerX, centerY, heightEllipse, widthEllipse, Math.PI / 4, 0, 2 * Math.PI); context.stroke(); As a result, I get this drawing: How can I calculate all the pixels on the circumference of an ellipse? For example, to make such calculations for a circle, I used the following formulas: for (let y = 0; y < r*2; y++) { P1=(x0-sqrt(r^2-(y-y0)^2), y); P2=(x0+sqrt(r^2-(y-y0)^2), y; }
Scan lines. Axis Aligned ellipse The first example is simple and only handles axis aligned ellipses. Call is scanEllipse(x, y, xRadius, yRadius); const ctx = can.getContext("2d"); scanEllipse(102, 64, 100, 30); scanEllipse(256, 64, 40, 60); function scanEllipse(x, y, h, v) { const hSqr = h * h; const scale = h / v; var i = -v; while (i <= v) { var ii = i * scale; var p1 = (hSqr - ii * ii) ** 0.5; ctx.fillStyle = i % 2 ? "#F00" : "#000"; ctx.fillRect(x - p1, y + i, p1 * 2, 1); i++; } } canvas { border: 1px solid black; } <canvas id="can" width="300" height="128"></canvas> Scan lines. Rotated ellipse This gets messy. To make sure it covers as many cases as possible I animated the function. I could not see any glitches but there may be some cases (very big ellipse or ellipses with very large eccentricity) where the floating point error may cause artifacts. Call is scanEllipse(x, y, xRadius, yRadius, ang); ang is in radians. const ctx = can.getContext("2d"); const quadRoots = (a, b, c) => { // find quadratic roots if (Math.abs(a) < 1e-6) { return b != 0 ? [-c / b] : [] } b /= a; var d = b * b - 4 * (c / a); if (d > 0) { d = d ** 0.5; return [0.5 * (-b + d), 0.5 * (-b - d)] } return d === 0 ? [0.5 * -b] : []; } function drawHLine(x, y, w) { ctx.fillStyle = y % 2 ? "#F00" : "#000"; ctx.fillRect(x, y, w, 1); } function scanEllipse(x, y, h, v, a) { const C = Math.cos(a), C2 = C * C; const S = Math.sin(a), S2 = S * S; const v2 = v * v, h2 = h * h; const A = v2 * C2 + h2 * S2; var i = 0, a, b, scan = true; function atY(y) { const B = 2 * y * C * S * (v2 - h2); const c = y * y *(v2 * S2 + h2 * C2 )- h2 * v2; return quadRoots(A, B, c); } while (scan) { [a, b] = atY(i); if (a !== undefined && b !== undefined) { drawHLine(x + a, y + i, b - a); if (i > 0) { [a, b] = atY(-i); drawHLine(x + a, y - i, b - a); } } else { scan = false; } i++; } } requestAnimationFrame(renderLoop); function renderLoop(time) { ctx.clearRect(0, 0, can.width, can.height); const h = Math.sin(time * 0.001) * 45 + 50; const v = Math.sin(time * 0.00333) * 35 + 40; scanEllipse(100, 100, h, v, time * 0.00077); requestAnimationFrame(renderLoop); } canvas { border: 1px solid black; } <canvas id="can" width="200" height="200"></canvas> Scan lines. Rotated ellipse edge only Addresses just the outside pixels. (to fit the rules of good pixel art line work). The function uses the same method as above by uses each previous row to workout which pixels are edge pixels. There is plenty of room for optimization and the animation is slowed just a little to let use see the pixels. Not that this version calculates the left and right edge using the center of each pixel row (eg y + 0.5). Using the top or bottom of the row makes for a lesser quality ellipse IMHO. Call is scanEllipse(x, y, xRadius, yRadius, ang); ang is in radians. const ctx = can.getContext("2d"); const quadRoots = (a, b, c) => { // find quadratic roots if (Math.abs(a) < 1e-6) { return b != 0 ? [-c / b] : [] } b /= a; var d = b * b - 4 * (c / a); if (d > 0) { d = d ** 0.5; return [0.5 * (-b + d), 0.5 * (-b - d)] } return d === 0 ? [0.5 * -b] : []; } function drawHLine(x, y, w) { ctx.fillStyle = y % 2 ? "#F00" : "#000"; ctx.fillRect(x, y, w, 1); } function scanEllipse(x, y, h, v, a) { const C = Math.cos(a), C2 = C * C; const S = Math.sin(a), S2 = S * S; const v2 = v * v, h2 = h * h; const A = v2 * C2 + h2 * S2; var i = 0, a1, b1, a2, b2, scan = true; var pa1, pb1, pa2, pb2; // p for previous function atY(y) { const B = 2 * y * C * S * (v2 - h2); const c = y * y *(v2 * S2 + h2 * C2 )- h2 * v2; return quadRoots(A, B, c); } const max = Math.max, min = Math.min; const addPx = (x, y) => ctx.fillRect(x, y, 1, 1); const addEdgeLine = (x1, x2, y) => { [x1, x2] = [min(x1, x2) | 0, max(x1, x2) | 0]; if (x1 == x2) { addPx(x1++, y); } while (x1 < x2) {addPx(x1++, y);} } while (scan) { [a1, b1] = atY(i - 0.5); if (a1 !== undefined && b1 !== undefined) { [a2, b2] = atY(-i +0.5); if (pa1) { addEdgeLine(pa1 + x, a1 + x, y + i - 1); addEdgeLine(pb1 + x, b1 + x, y + i - 1); if (i > 1) { addEdgeLine(pa2 + x, a2 + x, y - i + 1); addEdgeLine(pb2 + x, b2 + x, y - i + 1); } pa2 = a2; pb2 = b2; } else { pa2 = min(a1,a2); pb2 = max(b1,b2); } pa1 = a1; pb1 = b1; } else { // add last row (top bottom) if (pa1) { addEdgeLine(pa1 + x, pb1 + x, y + i - 1); addEdgeLine(pa2 + x, pb2 + x, y - i + 1); } scan = false; } i++; } } requestAnimationFrame(renderLoop); var tick = 0; function renderLoop(time) { if (tick++ % 4 === 0) { time /= 4; ctx.clearRect(0, 0, can.width, can.height); const h = Math.sin(time * 0.001) ** 2 * 34 + 10; const v = Math.sin(time * 0.00333) ** 2 * 35 + 10; scanEllipse(50, 50, h, v, time * 0.00077); } requestAnimationFrame(renderLoop); } canvas { border: 1px solid black; width: 400px; height: 400px; image-rendering: pixelated; } <canvas id="can" width="100" height="100"></canvas>
How to change color of circle when collision detection occurs?
As far as I understood it seems that even after changing the color when the collision is detected it reverts back to blue due to the else statement when it is compared between other circle and they are not colliding. So how would you solve this so that that the instance when the collision between any circle occurs it changes to red collision detection this.update = function() { for (let i = 0; i < circles.length; i++) { if (this !== circles[i] && getDistance(this.x, this.y, circles[i].x, circles[i].y) <= 200 * 200) { this.c = 'red'; circles[i].c = 'red'; resolveCollision(this, circles[i]); } else { this.c = 'blue'; circles[i].c = 'blue'; } } //wall deflection if (this.x - this.r <= 0 || this.x + this.r >= innerWidth) this.v.x *= -1 if (this.y - this.r <= 0 || this.y + this.r >= innerHeight) this.v.y *= -1 this.x += this.v.x; this.y += this.v.y; this.draw(); }; //deflection amongst other circles function resolveCollision(circle, othercircle) { const xVelocityDiff = circle.v.x - othercircle.v.x; const yVelocityDiff = circle.v.y - othercircle.v.y; const xDist = othercircle.x - circle.x; const yDist = othercircle.y - circle.y; if (xVelocityDiff * xDist + yVelocityDiff * yDist >= 0) { const angle = -Math.atan2(othercircle.y - circle.y, othercircle.x - circle.x); const m1 = circle.m; const m2 = othercircle.m; const u1 = rotate(circle.v, angle); const u2 = rotate(othercircle.v, angle); const v1 = { x: u1.x * (m1 - m2) / (m1 + m2) + u2.x * 2 * m2 / (m1 + m2), y: u1.y } const v2 = { x: u2.x * (m1 - m2) / (m1 + m2) + u1.x * 2 * m2 / (m1 + m2), y: u2.y } const vFinal1 = rotate(v1, -angle); const vFinal2 = rotate(v2, -angle); circle.v.x = vFinal1.x; circle.v.y = vFinal1.y; othercircle.v.x = vFinal2.x; othercircle.v.y = vFinal2.y; } }
Semaphores Use a semaphore that holds the collision state of the circle. Thus in your Circle.prototype would have something like these functions and properties Circle.prototype = { collided: false, // when true change color draw() { ctx.strokeStyle = this.collided ? "red" : "blue"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc(this.x, this.y, this.r - 1.5, 0, Math.PI * 2); ctx.stroke(); }, ... ... // in update update() { // when collision is detected set semaphore if (collision) { this.collided = true; } } } Counters Or you may want to only have the color change last for some time. You can modify the semaphore and use it as a counter. On collision set it to the number of frames to change color for. Circle.prototype = { collided: 0, draw() { ctx.strokeStyle = this.collided ? (this.collided--, "red") : "blue"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc(this.x, this.y, this.r - 1.5, 0, Math.PI * 2); ctx.stroke(); }, ... ... // in update update() { // when collision is detected set semaphore if (collision) { this.collided = 60; // 1 second at 60FPS } } } Example This example is taken from another answer I did earlier this year. As there is a lot of code I have highlighted the relevant code with /*= ANSWER CODE ============================================================== ... =============================================================================*/ The example uses counters and changes color for 30 frames after a collision with another ball or wall. I did not use a semaphore as all the balls would be red within a second. canvas.width = innerWidth -20; canvas.height = innerHeight -20; mathExt(); // creates some additional math functions const ctx = canvas.getContext("2d"); const GRAVITY = 0; const WALL_LOSS = 1; const BALL_COUNT = 10; // approx as will not add ball if space can not be found const MIN_BALL_SIZE = 6; const MAX_BALL_SIZE = 30; const VEL_MIN = 1; const VEL_MAX = 5; const MAX_RESOLUTION_CYCLES = 100; // Put too many balls (or too large) in the scene and the // number of collisions per frame can grow so large that // it could block the page. // If the number of resolution steps is above this value // simulation will break and balls can pass through lines, // get trapped, or worse. LOL const SHOW_COLLISION_TIME = 30; const balls = []; const lines = []; function Line(x1,y1,x2,y2) { this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; } Line.prototype = { draw() { ctx.moveTo(this.x1, this.y1); ctx.lineTo(this.x2, this.y2); }, reverse() { const x = this.x1; const y = this.y1; this.x1 = this.x2; this.y1 = this.y2; this.x2 = x; this.y2 = y; return this; } } function Ball(x, y, vx, vy, r = 45, m = 4 / 3 * Math.PI * (r ** 3)) { this.r = r; this.m = m this.x = x; this.y = y; this.vx = vx; this.vy = vy; /*= ANSWER CODE ==============================================================*/ this.collided = 0; /*============================================================================*/ } Ball.prototype = { update() { this.x += this.vx; this.y += this.vy; this.vy += GRAVITY; }, draw() { /*= ANSWER CODE ==============================================================*/ ctx.strokeStyle = this.collided ? (this.collided--, "#F00") : "#00F"; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc(this.x, this.y, this.r - 1.5, 0, Math.PI * 2); ctx.stroke(); /* ============================================================================*/ }, interceptLineTime(l, time) { const u = Math.interceptLineBallTime(this.x, this.y, this.vx, this.vy, l.x1, l.y1, l.x2, l.y2, this.r); if (u >= time && u <= 1) { return u; } }, checkBallBallTime(t, minTime) { return t > minTime && t <= 1; }, interceptBallTime(b, time) { const x = this.x - b.x; const y = this.y - b.y; const d = (x * x + y * y) ** 0.5; if (d > this.r + b.r) { const times = Math.circlesInterceptUnitTime( this.x, this.y, this.x + this.vx, this.y + this.vy, b.x, b.y, b.x + b.vx, b.y + b.vy, this.r, b.r ); if (times.length) { if (times.length === 1) { if(this.checkBallBallTime(times[0], time)) { return times[0] } return; } if (times[0] <= times[1]) { if(this.checkBallBallTime(times[0], time)) { return times[0] } if(this.checkBallBallTime(times[1], time)) { return times[1] } return } if(this.checkBallBallTime(times[1], time)) { return times[1] } if(this.checkBallBallTime(times[0], time)) { return times[0] } } } }, collideLine(l, time) { /*= ANSWER CODE ==============================================================*/ this.collided = SHOW_COLLISION_TIME; /*============================================================================*/ const x1 = l.x2 - l.x1; const y1 = l.y2 - l.y1; const d = (x1 * x1 + y1 * y1) ** 0.5; const nx = x1 / d; const ny = y1 / d; const u = (this.vx * nx + this.vy * ny) * 2; this.x += this.vx * time; this.y += this.vy * time; this.vx = (nx * u - this.vx) * WALL_LOSS; this.vy = (ny * u - this.vy) * WALL_LOSS; this.x -= this.vx * time; this.y -= this.vy * time; }, collide(b, time) { // b is second ball /*= ANSWER CODE ==============================================================*/ this.collided = SHOW_COLLISION_TIME; b.collided = SHOW_COLLISION_TIME; /*============================================================================*/ const a = this; const m1 = a.m; const m2 = b.m; a.x = a.x + a.vx * time; a.y = a.y + a.vy * time; b.x = b.x + b.vx * time; b.y = b.y + b.vy * time; const x = a.x - b.x const y = a.y - b.y const d = (x * x + y * y); const u1 = (a.vx * x + a.vy * y) / d const u2 = (x * a.vy - y * a.vx ) / d const u3 = (b.vx * x + b.vy * y) / d const u4 = (x * b.vy - y * b.vx ) / d const mm = m1 + m2; const vu3 = (m1 - m2) / mm * u1 + (2 * m2) / mm * u3; const vu1 = (m2 - m1) / mm * u3 + (2 * m1) / mm * u1; b.vx = x * vu1 - y * u4; b.vy = y * vu1 + x * u4; a.vx = x * vu3 - y * u2; a.vy = y * vu3 + x * u2; a.x = a.x - a.vx * time; a.y = a.y - a.vy * time; b.x = b.x - b.vx * time; b.y = b.y - b.vy * time; }, doesOverlap(ball) { const x = this.x - ball.x; const y = this.y - ball.y; return (this.r + ball.r) > ((x * x + y * y) ** 0.5); } } function canAdd(ball) { for(const b of balls) { if (ball.doesOverlap(b)) { return false } } return true; } function create(bCount) { lines.push(new Line(-10, 20, ctx.canvas.width + 10, 5)); lines.push((new Line(-10, ctx.canvas.height - 2, ctx.canvas.width + 10, ctx.canvas.height - 30)).reverse()); lines.push((new Line(30, -10, 4, ctx.canvas.height + 10)).reverse()); lines.push(new Line(ctx.canvas.width - 3, -10, ctx.canvas.width - 30, ctx.canvas.height + 10)); while (bCount--) { let tries = 100; while (tries--) { const dir = Math.rand(0, Math.TAU); const vel = Math.rand(VEL_MIN, VEL_MAX); const ball = new Ball( Math.rand(MAX_BALL_SIZE + 30, canvas.width - MAX_BALL_SIZE - 30), Math.rand(MAX_BALL_SIZE + 30, canvas.height - MAX_BALL_SIZE - 30), Math.cos(dir) * vel, Math.sin(dir) * vel, Math.rand(MIN_BALL_SIZE, MAX_BALL_SIZE), ); if (canAdd(ball)) { balls.push(ball); break; } } } } function resolveCollisions() { var minTime = 0, minObj, minBall, resolving = true, idx = 0, idx1, after = 0, e = 0; while (resolving && e++ < MAX_RESOLUTION_CYCLES) { // too main ball may create very lone resolution cycle. e limits this resolving = false; minObj = undefined; minBall = undefined; minTime = 1; idx = 0; for (const b of balls) { idx1 = idx + 1; while (idx1 < balls.length) { const b1 = balls[idx1++]; const time = b.interceptBallTime(b1, after); if (time !== undefined) { if (time <= minTime) { minTime = time; minObj = b1; minBall = b; resolving = true; } } } for (const l of lines) { const time = b.interceptLineTime(l, after); if (time !== undefined) { if (time <= minTime) { minTime = time; minObj = l; minBall = b; resolving = true; } } } idx ++; } if (resolving) { if (minObj instanceof Ball) { minBall.collide(minObj, minTime); } else { minBall.collideLine(minObj, minTime); } after = minTime; } } } create(BALL_COUNT); mainLoop(); function mainLoop() { ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); resolveCollisions(); for (const b of balls) { b.update() } for (const b of balls) { b.draw() } ctx.lineWidth = 1; ctx.strokeStyle = "#000"; ctx.beginPath(); for(const l of lines) { l.draw() } ctx.stroke(); requestAnimationFrame(mainLoop); } function mathExt() { Math.TAU = Math.PI * 2; Math.rand = (min, max) => Math.random() * (max - min) + min; Math.randI = (min, max) => Math.random() * (max - min) + min | 0; // only for positive numbers 32bit signed int Math.randItem = arr => arr[Math.random() * arr.length | 0]; // only for arrays with length < 2 ** 31 - 1 // contact points of two circles radius r1, r2 moving along two lines (a,e)-(b,f) and (c,g)-(d,h) [where (,) is coord (x,y)] Math.circlesInterceptUnitTime = (a, e, b, f, c, g, d, h, r1, r2) => { // args (x1, y1, x2, y2, x3, y3, x4, y4, r1, r2) const A = a * a, B = b * b, C = c * c, D = d * d; const E = e * e, F = f * f, G = g * g, H = h * h; var R = (r1 + r2) ** 2; const AA = A + B + C + F + G + H + D + E + b * c + c * b + f * g + g * f + 2 * (a * d - a * b - a * c - b * d - c * d - e * f + e * h - e * g - f * h - g * h); const BB = 2 * (-A + a * b + 2 * a * c - a * d - c * b - C + c * d - E + e * f + 2 * e * g - e * h - g * f - G + g * h); const CC = A - 2 * a * c + C + E - 2 * e * g + G - R; return Math.quadRoots(AA, BB, CC); } Math.quadRoots = (a, b, c) => { // find roots for quadratic if (Math.abs(a) < 1e-6) { return b != 0 ? [-c / b] : [] } b /= a; var d = b * b - 4 * (c / a); if (d > 0) { d = d ** 0.5; return [0.5 * (-b + d), 0.5 * (-b - d)] } return d === 0 ? [0.5 * -b] : []; } Math.interceptLineBallTime = (x, y, vx, vy, x1, y1, x2, y2, r) => { const xx = x2 - x1; const yy = y2 - y1; const d = vx * yy - vy * xx; if (d > 0) { // only if moving towards the line const dd = r / (xx * xx + yy * yy) ** 0.5; const nx = xx * dd; const ny = yy * dd; return (xx * (y - (y1 + nx)) - yy * (x -(x1 - ny))) / d; } } } <canvas id="canvas"></canvas>
const collided = { color: 'red', get current() { return this.color }, set current(clr) { if (this.color === 'red') { this.color = 'blue' } else { this.color = 'red' } } } this.update= function(){ for(let i=0;i<circles.length;i++){ if(this!==circles[i] && getDistance(this.x,this.y,circles[i].x,circles[i].y)<=200*200){ this.c=collided.current collided.current = this.c circles[i].c=collided.current resolveCollision(this,circles[i]); } // ... } } The trick is to use use getters and setters to ensure that the most recently used color value is never reapplied
First, split the if: // psudo-code if this is not circles[i], then if overlapping, then do something else do something else else do nothing Then, fix if this is not circles[i]: {x:100,y:100}!={x:100,y:100}, so either add id to circles and compare ids (my recommendation), or, compare .xs and .ys (less desired - what if they are equal but not same circle?), or, use JSON.stringify(a)==JSON.stringify(b). I would add .overlapping and before the loop, I'd add another loop setting all .overlapping to false, then, withing the modified original loop, I'd check if .overlapping is false, and then if there is a collision, I'd set .overlapping to true for both. Another way would be to create an array to hole overlapping circles' .ids and check if that array includes the current loop item's .id.
Clear canvas context gradually (mouse trail?)
If you see run the code snippet that i have, you'll this html canvas drawing thing that is segmented to color the arcs in a gradient. I'm trying to figure out how to gradually clear the context of old 'arcs' from the tail end of the drawing similar to a 'mouse trail' effect, perhaps similar to this: https://imgur.com/a/2Lr9IYq I'm thinking, perhaps that somehow, once the total counter goes above the segment count, it clears itself but im not quite sure how to do that. Grateful if anyone can point me in the right direction! var c = document.querySelector("canvas"), ctx = c.getContext("2d"), colors = [ {r: 0, g: 0, b: 0, a:1}, {r: 255, g: 255, b: 255, a:1}, ], cIndex = 0, maxColors = colors.length, total = 0, segment = 1000, isDown = false, px, py; setSize(); c.onmousedown = c.ontouchstart = function(e) { isDown = true; var pos = getPos(e); px = pos.x; py = pos.y; }; c.onmousemove = c.ontouchmove = function(e) {if (isDown) plot(e)}; c.onmouseup = c.ontouchend = function(e) { e.preventDefault(); isDown = false }; function getPos(e) { // e.preventDefault(); if (e.touches) e = e.touches[0]; var r = c.getBoundingClientRect(); return { x: e.clientX - r.left, y: e.clientY - r.top } } function plot(e) { var pos = getPos(e); plotLine(ctx, px, py, pos.x, pos.y); px = pos.x; py = pos.y; } function plotLine(ctx, x1, y1, x2, y2) { var diffX = Math.abs(x2 - x1), diffY = Math.abs(y2 - y1), dist = Math.sqrt(diffX * diffX + diffY * diffY), step = dist / 50, i = 0, t, b, x, y; while (i < dist) { t = Math.min(1, i / dist); x = x1 + (x2 - x1) * t; y = y1 + (y2 - y1) * t; // ctx.shadowBlur = 500; // ctx.shadowOffsetX = 0; // ctx.shadowOffsetY = 0; // ctx.shadowColor = getColor(); // console.log(getColor()) ctx.fillStyle = getColor(); ctx.beginPath(); ctx.arc(x, y, 25, 0, Math.PI*2); ctx.fill(); i += step; } function getColor() { var r, g, b, a, t, c1, c2; c1 = colors[cIndex]; c2 = colors[(cIndex + 1) % maxColors]; t = Math.min(1, total / segment); if (++total > segment) { total = 0; if (++cIndex >= maxColors) cIndex = 0; } r = c1.r + (c2.r - c1.r) * t; g = c1.g + (c2.g - c1.g) * t; b = c1.b + (c2.b - c1.b) * t; a = c1.a + (c2.a - c1.a) * t; return "rgb(" + (r|0) + "," + (g|0) + "," + (b|0) + "," + (a) + ")"; } } window.onresize = setSize; function setSize() { c.width = window.innerWidth; c.height = window.innerHeight; } html, body { margin:0; padding:0; } body { padding: 0px; } <canvas id="myCanvas" ></canvas>
Drawing an outlined ellipse with thickness in JS
I want to draw a basic axis-aligned ellipse in Javascript without the Canvas/Context methods provided (they add anti-aliasing which I don't want!) So far, I got this working, but the thickness is still wrong. var canvas = document.getElementById('myCanvas'); var ctx = canvas.getContext('2d'); var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); function setPixel(x, y, r, g, b) { var index = (y * imageData.width + x) * 4; imageData.data[index + 0] = r; imageData.data[index + 1] = g; imageData.data[index + 2] = b; imageData.data[index + 3] = 255; } function drawEllipse(x1, y1, x2, y2, thickness, r, g, b) { var radX = (x2 - x1) * 0.5; var radY = (y2 - y1) * 0.5; var cenX = (x1 + x2) * 0.5; var cenY = (y1 + y2) * 0.5; var aspectX = 1.0; var aspectY = 1.0; var radMax = Math.max(radX, radY); if (radX > radY) aspectY = radX / radY; else aspectX = radY / radX; for (var x = x1; x < x2; x++) { for (var y = y1; y < y2; y++) { var dx = Math.abs(x - cenX) * aspectX; var dy = Math.abs(y - cenY) * aspectY; var d = Math.sqrt(dx*dx + dy*dy); var side1 = d < radMax && d > radMax - thickness; if (side1) setPixel(x, y, r, g, b); } } } drawEllipse(0, 0, canvas.width - 1, canvas.height - 1, 20, 0, 0, 0); ctx.putImageData(imageData, 0, 0); #myCanvas { background: white; } <canvas id="myCanvas" width="120" height="60"></canvas> Alternatively on JSBin: https://jsbin.com/diwewimuya/edit?html,css,js,output
How to draw/Form circle with two points?
I need to draw a circle and i have only two points.Now i need to find center point and radius of the circle? You can form the circle in clock wise direction. Thanks in advance
Here is a Brute Force approach to the problem. EDIT Added a max iterations limit to cut off calculations if the line between the two points is almost straight along x (meaning a radius would be nearing Infinity) Also animations, because that makes everything better :) var canvas = document.body.appendChild(document.createElement("canvas")); var ctx = canvas.getContext("2d"); canvas.width = 1000; canvas.height = 1000; var points = [ { x: parseInt(prompt("x1", "110")), y: parseInt(prompt("y1", "120")), r: 5 }, { x: parseInt(prompt("x2", "110")), y: parseInt(prompt("y2", "60")), r: 5 }, ]; function calculateRemainingPoint(points, x, precision, maxIteration) { if (x === void 0) { x = 0; } if (precision === void 0) { precision = 0.001; } if (maxIteration === void 0) { maxIteration = 100000; } var newPoint = { x: x, y: (points[0].y + points[1].y) / 2, r: 50 }; var d0 = distance(points[0].x, points[0].y, x, newPoint.y); var d1 = distance(points[1].x, points[1].y, x, newPoint.y); var iteration = 0; //Bruteforce approach while (Math.abs(d0 - d1) > precision && iteration < maxIteration) { var oldDiff = Math.abs(d0 - d1); var oldY = newPoint.y; iteration++; newPoint.y += oldDiff / 10; d0 = distance(points[0].x, points[0].y, x, newPoint.y); d1 = distance(points[1].x, points[1].y, x, newPoint.y); var diff_1 = Math.abs(d0 - d1); if (diff_1 > oldDiff) { newPoint.y = oldY - oldDiff / 10; d0 = distance(points[0].x, points[0].y, x, newPoint.y); d1 = distance(points[1].x, points[1].y, x, newPoint.y); } } var diff = (points[0].x + points[1].x) / points[0].x; newPoint.r = d0; return newPoint; } points.push(calculateRemainingPoint(points)); function distance(x1, y1, x2, y2) { var a = x1 - x2; var b = y1 - y2; return Math.sqrt(a * a + b * b); } function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.beginPath(); ctx.moveTo(-canvas.width, canvas.height / 2); ctx.lineTo(canvas.width, canvas.height / 2); ctx.stroke(); ctx.closePath(); ctx.beginPath(); ctx.moveTo(canvas.width / 2, -canvas.height); ctx.lineTo(canvas.width / 2, canvas.height); ctx.stroke(); ctx.closePath(); for (var pointIndex = 0; pointIndex < points.length; pointIndex++) { var point = points[pointIndex]; ctx.beginPath(); ctx.arc(point.x + canvas.width / 2, canvas.height / 2 - point.y, point.r, 0, Math.PI * 2); ctx.arc(point.x + canvas.width / 2, canvas.height / 2 - point.y, 2, 0, Math.PI * 2); ctx.stroke(); ctx.closePath(); } } setInterval(function () { points = points.slice(0, 2); points[Math.floor(Math.random() * points.length) % points.length][Math.random() > 0.5 ? 'x' : 'y'] = Math.random() * canvas.width - canvas.width / 2; setTimeout(function () { points.push(calculateRemainingPoint(points)); requestAnimationFrame(draw); }, 1000 / 60); }, 1000); draw();
No that is impossible. Create two circles with the same radius at centerpoints A + B. At the intersection of these two circles create an circle with the same radius.... Then make the same with an other radius....