first commit
This commit is contained in:
parent
94a6e93b89
commit
ba53f23f30
16
index.html
Normal file
16
index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Document</title>
|
||||
<script src="script/main.js"></script>
|
||||
<link rel="stylesheet" href="style/main.css" />
|
||||
</head>
|
||||
<body>
|
||||
<canvas></canvas>
|
||||
<section class="gui">
|
||||
<h2 class="label">Particles</h2>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
86
script/main.js
Normal file
86
script/main.js
Normal file
@ -0,0 +1,86 @@
|
||||
window.onload = function () {
|
||||
var Particle = /** @class */ (function () {
|
||||
function Particle(x, y, color, radius) {
|
||||
this.vx = 0;
|
||||
this.vy = 0;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.color = color;
|
||||
this.radius = radius;
|
||||
}
|
||||
Particle.prototype.draw = function () {
|
||||
ctx.beginPath();
|
||||
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
|
||||
ctx.fillStyle = this.color;
|
||||
ctx.fill();
|
||||
};
|
||||
Particle.DEFAULT_RADIUS = 2.5;
|
||||
return Particle;
|
||||
}());
|
||||
var canvas = document.querySelector("canvas");
|
||||
var ctx = canvas.getContext("2d");
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
window.addEventListener("resize", function () {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
});
|
||||
var particles = [];
|
||||
function randomInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||
}
|
||||
function makeGroup(number, color, options) {
|
||||
var _a;
|
||||
var group = [];
|
||||
for (var i = 0; i < number; i++) {
|
||||
var particle = new Particle(randomInt(0, canvas.width), randomInt(0, canvas.height), color, (_a = options.radius) !== null && _a !== void 0 ? _a : Particle.DEFAULT_RADIUS);
|
||||
group.push(particle);
|
||||
particles.push(particle);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
function interaction(group1, group2, options) {
|
||||
var _a, _b, _c;
|
||||
if (options === void 0) { options = {}; }
|
||||
options.g = (_a = options.g) !== null && _a !== void 0 ? _a : 0.1;
|
||||
options.maxDistance = (_b = options.maxDistance) !== null && _b !== void 0 ? _b : 100;
|
||||
options.minDistance = (_c = options.minDistance) !== null && _c !== void 0 ? _c : 0;
|
||||
for (var i = 0; i < group1.length; i++) {
|
||||
var fx = 0;
|
||||
var fy = 0;
|
||||
for (var j = 0; j < group2.length; j++) {
|
||||
var a = group1[i];
|
||||
var b = group2[j];
|
||||
var dx = a.x - b.x;
|
||||
var dy = a.y - b.y;
|
||||
var d = Math.sqrt(dx * dx + dy * dy);
|
||||
if (d > 0 && d < options.maxDistance && d > options.minDistance) {
|
||||
var F = options.g / d;
|
||||
fx += F * dx;
|
||||
fy += F * dy;
|
||||
}
|
||||
a.vx = (a.vx + fx) * 0.5;
|
||||
a.vy = (a.vy + fy) * 0.5;
|
||||
a.x += a.vx * 0.005;
|
||||
a.y += a.vy * 0.005;
|
||||
}
|
||||
}
|
||||
}
|
||||
var blue = makeGroup(5000, "#0000ff", { radius: 1 });
|
||||
var red = makeGroup(1000, "#ff0000", { radius: 2.5 });
|
||||
var green = makeGroup(50, "#00ff00", { radius: 4 });
|
||||
function animate() {
|
||||
interaction(red, red, { g: -0.05, maxDistance: 250 });
|
||||
interaction(green, red, { g: -0.1, maxDistance: 500 });
|
||||
interaction(red, green, { g: -0.05, maxDistance: 250 });
|
||||
interaction(blue, red, { g: -0.4, maxDistance: 250 });
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.fillStyle = "#000000";
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
particles.forEach(function (particle) {
|
||||
particle.draw();
|
||||
});
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
animate();
|
||||
};
|
130
script/main.ts
Normal file
130
script/main.ts
Normal file
@ -0,0 +1,130 @@
|
||||
window.onload = function () {
|
||||
class Particle {
|
||||
public x: number;
|
||||
public y: number;
|
||||
public radius: number;
|
||||
public color: string;
|
||||
public vx: number = 0;
|
||||
public vy: number = 0;
|
||||
|
||||
public static DEFAULT_RADIUS = 2.5;
|
||||
|
||||
public constructor(x: number, y: number, color: string, radius: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.color = color;
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public draw() {
|
||||
ctx.beginPath();
|
||||
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
|
||||
ctx.fillStyle = this.color;
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
|
||||
const canvas = document.querySelector("canvas") as HTMLCanvasElement;
|
||||
const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;
|
||||
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
|
||||
window.addEventListener("resize", () => {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
});
|
||||
|
||||
const particles: Particle[] = [];
|
||||
|
||||
function randomInt(min: number, max: number) {
|
||||
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||
}
|
||||
|
||||
function makeGroup(
|
||||
number: number,
|
||||
color: string,
|
||||
options: { radius?: number }
|
||||
) {
|
||||
const group: Particle[] = [];
|
||||
|
||||
for (let i = 0; i < number; i++) {
|
||||
const particle = new Particle(
|
||||
randomInt(0, canvas.width),
|
||||
randomInt(0, canvas.height),
|
||||
color,
|
||||
options.radius ?? Particle.DEFAULT_RADIUS
|
||||
);
|
||||
|
||||
group.push(particle);
|
||||
particles.push(particle);
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
type Options = {
|
||||
minDistance?: number;
|
||||
maxDistance?: number;
|
||||
g?: number;
|
||||
};
|
||||
|
||||
function interaction(
|
||||
group1: Particle[],
|
||||
group2: Particle[],
|
||||
options: Options = {}
|
||||
) {
|
||||
options.g = options.g ?? 0.1;
|
||||
options.maxDistance = options.maxDistance ?? 100;
|
||||
options.minDistance = options.minDistance ?? 0;
|
||||
|
||||
for (let i = 0; i < group1.length; i++) {
|
||||
let fx = 0;
|
||||
let fy = 0;
|
||||
|
||||
for (let j = 0; j < group2.length; j++) {
|
||||
let a = group1[i];
|
||||
let b = group2[j];
|
||||
|
||||
const dx = a.x - b.x;
|
||||
const dy = a.y - b.y;
|
||||
const d = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (d > 0 && d < options.maxDistance && d > options.minDistance) {
|
||||
const F = options.g / d;
|
||||
fx += F * dx;
|
||||
fy += F * dy;
|
||||
}
|
||||
|
||||
a.vx = (a.vx + fx) * 0.5;
|
||||
a.vy = (a.vy + fy) * 0.5;
|
||||
a.x += a.vx * 0.005;
|
||||
a.y += a.vy * 0.005;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const blue = makeGroup(5000, "#0000ff", { radius: 1 });
|
||||
const red = makeGroup(1000, "#ff0000", { radius: 2.5 });
|
||||
const green = makeGroup(50, "#00ff00", { radius: 4 });
|
||||
|
||||
function animate() {
|
||||
interaction(red, red, { g: -0.05, maxDistance: 250 });
|
||||
interaction(green, red, { g: -0.1, maxDistance: 500 });
|
||||
interaction(red, green, { g: -0.05, maxDistance: 250 });
|
||||
interaction(blue, red, { g: -0.4, maxDistance: 250 });
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
ctx.fillStyle = "#000000";
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
particles.forEach((particle) => {
|
||||
particle.draw();
|
||||
});
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
animate();
|
||||
};
|
29
style/main.css
Normal file
29
style/main.css
Normal file
@ -0,0 +1,29 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Roboto", sans-serif;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gui {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 100;
|
||||
background: rgba(255, 255, 255, 0.0666666667);
|
||||
color: #ffffff;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.gui .label {
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: rgba(255, 255, 255, 0.5333333333);
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=main.css.map */
|
1
style/main.css.map
Normal file
1
style/main.css.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":["main.scss"],"names":[],"mappings":"AAAA;EACC;EACA;EACA;;;AAGD;EACC;EACA;;;AAGD;EACC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACC;EACA;EACA;EACA","file":"main.css"}
|
28
style/main.scss
Normal file
28
style/main.scss
Normal file
@ -0,0 +1,28 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Roboto", sans-serif;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gui {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 100;
|
||||
background: #ffffff11;
|
||||
color: #ffffff;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
|
||||
.label {
|
||||
text-transform: uppercase;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #ffffff88;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user