- Dapatkan pautan
- X
- E-mel
- Apl Lain
Demo
HTML view ▼
<style>
.labu {
width: 100%;
height: 100%;
margin: 0;
background: rgb(30,30,30);
overflow: hidden;
box-shadow: 0 0 6px 6px rgba(50, 50, 50, 0.5);
}
#C {
width: 100%;
height: 100%;
}
</style>
<script>
window.onload = function () {
let ctx = document.getElementById("C"),
c = ctx.getContext("2d"),
w,
h;
fitCanvas();
class attractor {
constructor(id) {
this.ind = id;
this.controlledByMouse = false;
if (id == 0) {
this.controlledByMouse = true;
}
this.x = Math.random() * w;
this.y = Math.random() * h;
this.vAng = Math.random() * 2 * Math.PI - Math.PI;
this.vx = 0; //att_spd*Math.cos(this.vAng);
this.vy = 0; //att_spd*Math.sin(this.vAng);
this.ax = 0;
this.ay = 0;
this.polarity = 1;
this.color = "hsl(216,100%,50%)";
if (id % 2 == 0) {
this.polarity = -1;
this.color = "hsl(0,100%,50%)";
let ang, x, y;
for (let i = 0; i < LPAtt; i++) {
ang = (i * 2 * Math.PI) / LPAtt;
x = Math.cos(ang);
y = Math.sin(ang);
lines.push(new line(this, x, y));
}
}
}
calc_forces(others) {
let d, ang, a_r;
for (let i = 0, len = others.length; i < len; i++) {
ang = Math.atan2(others[i].y - this.y, others[i].x - this.x);
d = Math.sqrt(
Math.pow(others[i].x - this.x, 2) + Math.pow(others[i].y - this.y, 2)
);
if (this == others[i] || d > att_max_d) {
continue;
}
a_r = 1;
if (this.polarity == others[i].polarity) {
a_r = -1;
}
if (d > att_size * 2) {
this.ax +=
(a_r * (att_spd / (att_max_d / (d * d * d))) * Math.cos(ang)) / len;
this.ay +=
(a_r * (att_spd / (att_max_d / (d * d * d))) * Math.sin(ang)) / len;
}
if (!this.controlledByMouse) {
let counter = 0;
while (d < att_size * 2 && counter < 100) {
this.ax += -0.1 * Math.cos(ang);
this.ay += -0.1 * Math.sin(ang);
this.update();
d = Math.sqrt(
Math.pow(others[i].x - this.x, 2) +
Math.pow(others[i].y - this.y, 2)
);
counter++;
}
}
}
}
update(m) {
if (this.controlledByMouse) {
this.x = m.x;
this.y = m.y;
if (mouseDown && mouseCounter == 0) {
this.polarity *= -1;
if (this.polarity > 0) {
this.color = "hsl(216,100%,50%)";
} else {
this.color = "hsl(0,100%,50%)";
}
mouseCounter++;
}
if (!mouseDown && mouseCounter != 0) {
mouseCounter = 0;
}
} else {
this.vx += this.ax;
this.vy += this.ay;
this.vx *= 0.7;
this.vy *= 0.7;
this.x += this.vx;
this.y += this.vy;
this.ax = 0;
this.ay = 0;
if (this.x < att_size) {
this.x -= this.x - att_size;
this.vx *= -1;
}
if (this.x > w - att_size) {
this.x -= this.x - w + att_size;
this.vx *= -1;
}
if (this.y < att_size) {
this.y -= this.y - att_size;
this.vy *= -1;
}
if (this.y > h - att_size) {
this.y -= this.y - h + att_size;
this.vy *= -1;
}
}
}
show() {
c.beginPath();
c.arc(this.x, this.y, att_size, 0, 2 * Math.PI);
c.fillStyle = this.color;
c.lineWidth = 1;
c.fill();
}
}
class line {
constructor(parent, x, y) {
this.p = parent;
this.ox = x;
this.oy = y;
this.tail = [];
this.reset();
this.tail.push({ x: this.p.x, y: this.p.y });
this.tail.push({ x: this.x, y: this.y });
}
reset() {
this.x = this.p.x + this.ox;
this.y = this.p.y + this.oy;
}
update() {
this.tail = [];
for (let i = 0; i < segment_num; i++) {
let earlyExit = false,
dpos = 1e6,
dneg = 1e6;
let v2x,
v2y,
d,
vx = 0,
vy = 0;
for (let t of att) {
v2x = (t.x - this.x) * t.polarity;
v2y = (t.y - this.y) * t.polarity;
d = Math.sqrt(Math.pow(v2x, 2) + Math.pow(v2y, 2));
if (d < dneg && t.polarity == -1) {
dneg = d;
}
if (d < dpos && t.polarity == 1) {
dpos = d;
}
if (d < segment_length * 1.2 && t.polarity == 1) {
earlyExit = true;
}
vx += v2x / (d * d);
vy += v2y / (d * d);
}
let vd = Math.sqrt(Math.pow(vx, 2) + Math.pow(vy, 2));
vx /= vd;
vy /= vd;
this.x += vx * segment_length;
this.y += vy * segment_length;
if (earlyExit) {
break;
}
this.tail.push({ x: this.x, y: this.y });
}
}
show() {
c.beginPath();
for (let i = 0, len = this.tail.length; i < len; i++) {
c.lineTo(this.tail[i].x, this.tail[i].y);
}
c.strokeStyle = "white";
c.lineWidth = line_width;
c.stroke();
}
}
let LPAtt = 36,
att_num = 40,
att_spd = 0.001,
segment_length = 8,
segment_num = 120,
att_max_d = 150;
let att_size = segment_length + 1,
line_width = 0.5;
let mouse = { x: false, y: false },
last_mouse = {},
mouseDown = false,
mouseCounter = 0;
let att = [],
lines = [];
for (let i = 0; i < att_num; i++) {
att.push(new attractor(i));
}
function draw() {
for (let i = 0, len = att.length; i < len; i++) {
att[i].calc_forces(att);
att[i].update(mouse);
}
for (let i = 0, len = lines.length; i < len; i++) {
lines[i].reset();
lines[i].update();
lines[i].show();
}
for (let i = 0, len = att.length; i < len; i++) {
att[i].show();
}
}
ctx.addEventListener(
"mousemove",
function (e) {
last_mouse.x = mouse.x;
last_mouse.y = mouse.y;
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
},
false
);
ctx.addEventListener(
"mousedown",
function (e) {
mouseDown = true;
},
false
);
ctx.addEventListener(
"mouseup",
function (e) {
mouseDown = false;
},
false
);
function fitCanvas() {
w = ctx.width = window.innerWidth;
h = ctx.height = window.innerHeight;
}
function loop() {
fitCanvas();
draw();
window.requestAnimationFrame(loop);
}
window.requestAnimationFrame(loop);
};
</script>
.labu {
width: 100%;
height: 100%;
margin: 0;
background: rgb(30,30,30);
overflow: hidden;
box-shadow: 0 0 6px 6px rgba(50, 50, 50, 0.5);
}
#C {
width: 100%;
height: 100%;
}
</style>
<script>
window.onload = function () {
let ctx = document.getElementById("C"),
c = ctx.getContext("2d"),
w,
h;
fitCanvas();
class attractor {
constructor(id) {
this.ind = id;
this.controlledByMouse = false;
if (id == 0) {
this.controlledByMouse = true;
}
this.x = Math.random() * w;
this.y = Math.random() * h;
this.vAng = Math.random() * 2 * Math.PI - Math.PI;
this.vx = 0; //att_spd*Math.cos(this.vAng);
this.vy = 0; //att_spd*Math.sin(this.vAng);
this.ax = 0;
this.ay = 0;
this.polarity = 1;
this.color = "hsl(216,100%,50%)";
if (id % 2 == 0) {
this.polarity = -1;
this.color = "hsl(0,100%,50%)";
let ang, x, y;
for (let i = 0; i < LPAtt; i++) {
ang = (i * 2 * Math.PI) / LPAtt;
x = Math.cos(ang);
y = Math.sin(ang);
lines.push(new line(this, x, y));
}
}
}
calc_forces(others) {
let d, ang, a_r;
for (let i = 0, len = others.length; i < len; i++) {
ang = Math.atan2(others[i].y - this.y, others[i].x - this.x);
d = Math.sqrt(
Math.pow(others[i].x - this.x, 2) + Math.pow(others[i].y - this.y, 2)
);
if (this == others[i] || d > att_max_d) {
continue;
}
a_r = 1;
if (this.polarity == others[i].polarity) {
a_r = -1;
}
if (d > att_size * 2) {
this.ax +=
(a_r * (att_spd / (att_max_d / (d * d * d))) * Math.cos(ang)) / len;
this.ay +=
(a_r * (att_spd / (att_max_d / (d * d * d))) * Math.sin(ang)) / len;
}
if (!this.controlledByMouse) {
let counter = 0;
while (d < att_size * 2 && counter < 100) {
this.ax += -0.1 * Math.cos(ang);
this.ay += -0.1 * Math.sin(ang);
this.update();
d = Math.sqrt(
Math.pow(others[i].x - this.x, 2) +
Math.pow(others[i].y - this.y, 2)
);
counter++;
}
}
}
}
update(m) {
if (this.controlledByMouse) {
this.x = m.x;
this.y = m.y;
if (mouseDown && mouseCounter == 0) {
this.polarity *= -1;
if (this.polarity > 0) {
this.color = "hsl(216,100%,50%)";
} else {
this.color = "hsl(0,100%,50%)";
}
mouseCounter++;
}
if (!mouseDown && mouseCounter != 0) {
mouseCounter = 0;
}
} else {
this.vx += this.ax;
this.vy += this.ay;
this.vx *= 0.7;
this.vy *= 0.7;
this.x += this.vx;
this.y += this.vy;
this.ax = 0;
this.ay = 0;
if (this.x < att_size) {
this.x -= this.x - att_size;
this.vx *= -1;
}
if (this.x > w - att_size) {
this.x -= this.x - w + att_size;
this.vx *= -1;
}
if (this.y < att_size) {
this.y -= this.y - att_size;
this.vy *= -1;
}
if (this.y > h - att_size) {
this.y -= this.y - h + att_size;
this.vy *= -1;
}
}
}
show() {
c.beginPath();
c.arc(this.x, this.y, att_size, 0, 2 * Math.PI);
c.fillStyle = this.color;
c.lineWidth = 1;
c.fill();
}
}
class line {
constructor(parent, x, y) {
this.p = parent;
this.ox = x;
this.oy = y;
this.tail = [];
this.reset();
this.tail.push({ x: this.p.x, y: this.p.y });
this.tail.push({ x: this.x, y: this.y });
}
reset() {
this.x = this.p.x + this.ox;
this.y = this.p.y + this.oy;
}
update() {
this.tail = [];
for (let i = 0; i < segment_num; i++) {
let earlyExit = false,
dpos = 1e6,
dneg = 1e6;
let v2x,
v2y,
d,
vx = 0,
vy = 0;
for (let t of att) {
v2x = (t.x - this.x) * t.polarity;
v2y = (t.y - this.y) * t.polarity;
d = Math.sqrt(Math.pow(v2x, 2) + Math.pow(v2y, 2));
if (d < dneg && t.polarity == -1) {
dneg = d;
}
if (d < dpos && t.polarity == 1) {
dpos = d;
}
if (d < segment_length * 1.2 && t.polarity == 1) {
earlyExit = true;
}
vx += v2x / (d * d);
vy += v2y / (d * d);
}
let vd = Math.sqrt(Math.pow(vx, 2) + Math.pow(vy, 2));
vx /= vd;
vy /= vd;
this.x += vx * segment_length;
this.y += vy * segment_length;
if (earlyExit) {
break;
}
this.tail.push({ x: this.x, y: this.y });
}
}
show() {
c.beginPath();
for (let i = 0, len = this.tail.length; i < len; i++) {
c.lineTo(this.tail[i].x, this.tail[i].y);
}
c.strokeStyle = "white";
c.lineWidth = line_width;
c.stroke();
}
}
let LPAtt = 36,
att_num = 40,
att_spd = 0.001,
segment_length = 8,
segment_num = 120,
att_max_d = 150;
let att_size = segment_length + 1,
line_width = 0.5;
let mouse = { x: false, y: false },
last_mouse = {},
mouseDown = false,
mouseCounter = 0;
let att = [],
lines = [];
for (let i = 0; i < att_num; i++) {
att.push(new attractor(i));
}
function draw() {
for (let i = 0, len = att.length; i < len; i++) {
att[i].calc_forces(att);
att[i].update(mouse);
}
for (let i = 0, len = lines.length; i < len; i++) {
lines[i].reset();
lines[i].update();
lines[i].show();
}
for (let i = 0, len = att.length; i < len; i++) {
att[i].show();
}
}
ctx.addEventListener(
"mousemove",
function (e) {
last_mouse.x = mouse.x;
last_mouse.y = mouse.y;
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
},
false
);
ctx.addEventListener(
"mousedown",
function (e) {
mouseDown = true;
},
false
);
ctx.addEventListener(
"mouseup",
function (e) {
mouseDown = false;
},
false
);
function fitCanvas() {
w = ctx.width = window.innerWidth;
h = ctx.height = window.innerHeight;
}
function loop() {
fitCanvas();
draw();
window.requestAnimationFrame(loop);
}
window.requestAnimationFrame(loop);
};
</script>
JS dipetik dari codepen.io/Mertl/pen/poQGmVp
Catatan oleh
Orandableg
- Dapatkan pautan
- X
- E-mel
- Apl Lain
Ulasan