var _a, _b, _c, _d, _e, _f, _g; var SLIDER_MIN = 50; var SLIDER_MAX = 1000; var SLIDER_STEP = 50; var SLIDER_DEFAULT = 350; var MAX_INTERACTION_NUMBER = 20; var MIN_INTENSITY = 1; var MAX_INTENSITY = 1000; var DEFAULT_INTENSITY = 100; var INTENSITY_STEP = 1; var INTENSITY_DIVIDER = 10000; var DISTANCE_MIN = 10; var DISTANCE_MAX = 500; var DISTANCE_STEP = 10; var DISTANCE_DEFAULT = 200; var Group1 = 0; var Group2 = 1; var canvas = document.querySelector("canvas"); var ctx = canvas.getContext("2d"); canvas.width = window.innerWidth; canvas.height = window.innerHeight; 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) { ctx.fillStyle = ColorsHex[this.color]; ctx.fillRect(this.x, this.y, this.radius, this.radius); }; Particle.DEFAULT_RADIUS = 5; return Particle; }()); var paused = true; var particles = []; var interactions = []; var ColorsHex = Object.freeze({ red: "#f91d4d", green: "#0db342", blue: "#4a4ad7", yellow: "#f0e246", magenta: "#d742d7", cyan: "#42cedb", }); var colors = { red: null, green: null, blue: null, yellow: null, magenta: null, cyan: null, }; function reset() { particles.forEach(function (particle) { particle.x = randomInt(0, canvas.width); particle.y = randomInt(0, canvas.height); }); paused = true; var img = document.querySelector(".play-pause img"); img.src = "/assets/images/svg/play_arrow.svg"; } function addColor(color, autoGroup) { if (autoGroup === void 0) { autoGroup = true; } if (autoGroup) colors[color] = makeGroup(350, color, { radius: Particle.DEFAULT_RADIUS }); var container = document.querySelector(".particle-containers"); var particle = document.createElement("div"); particle.classList.add("particle-container"); particle.classList.add(color); var head = document.createElement("div"); head.classList.add("container-head"); head.innerHTML = "
".concat(SLIDER_MIN.toLocaleString("en-US"), "
").concat(SLIDER_MAX.toLocaleString("en-US"), "
"); var input = range.querySelector("input"); input.addEventListener("input", function () { var value = parseInt(input.value); particleSetting.innerHTML = "Particle number : ".concat(value.toLocaleString("en-US"), ""); particles = particles.filter(function (p) { return p.color !== color; }); colors[color] = makeGroup(value, color, { radius: Particle.DEFAULT_RADIUS, }); interactions = interactions.map(function (itn) { if (itn.group1[0].color === color) { itn.group1 = colors[color]; } else if (itn.group2[0].color === color) { itn.group2 = colors[color]; } return itn; }); }); particle.appendChild(head); particle.appendChild(particleSetting); particle.appendChild(range); container.appendChild(particle); } function colorSelector(selected, group, interaction) { var selector = document.createElement("div"); selector.classList.add("color-selector"); var selectedColor = document.createElement("button"); selectedColor.classList.add("color"); selectedColor.classList.add(selected); var colorList = document.createElement("div"); colorList.classList.add("color-list"); selectedColor.addEventListener("click", function (e) { e.stopPropagation(); if (colorList.classList.contains("show")) { colorList.classList.remove("show"); } else { var colorButtons = document.querySelectorAll(".color-list"); colorButtons.forEach(function (colorButton) { if (colorButton.classList.contains("show")) { colorButton.classList.remove("show"); } }); colorList.classList.add("show"); colorList.innerHTML = ""; var _loop_1 = function (color) { if (!colors[color]) return "continue"; var colorButton = document.createElement("button"); colorButton.classList.add("color"); colorButton.classList.add(color); colorButton.addEventListener("click", function (e) { e.stopPropagation(); selectedColor.classList.remove(selected); selected = color; selectedColor.classList.add(selected); colorList.classList.remove("show"); switch (group) { case Group1: interaction.group1 = colors[color]; break; case Group2: interaction.group2 = colors[color]; break; } }); colorList.appendChild(colorButton); }; for (var color in colors) { _loop_1(color); } } }); selector.appendChild(selectedColor); selector.appendChild(colorList); return selector; } function addInteraction(interaction) { interactions.push(interaction); var isAttractionForce = true; var container = document.querySelector(".interaction-containers"); var interactionContainer = document.createElement("div"); interactionContainer.classList.add("interaction-container"); var colors = document.createElement("div"); colors.classList.add("colors"); var color1 = colorSelector(interaction.group1[0].color, 0, interaction); var color2 = colorSelector(interaction.group2[0].color, 1, interaction); var liaison = document.createElement("h3"); liaison.classList.add("setting"); if (isAttractionForce) { liaison.textContent = "is attracted to"; } else { liaison.textContent = "is repulsed by"; } var close = document.createElement("button"); close.classList.add("close"); close.classList.add("interaction"); close.textContent = "тип"; colors.appendChild(color1); colors.appendChild(liaison); colors.appendChild(color2); colors.appendChild(close); var forceContainer = document.createElement("div"); forceContainer.classList.add("force-container"); forceContainer.innerHTML = "".concat(MIN_INTENSITY.toLocaleString("en-US"), "
").concat(MAX_INTENSITY.toLocaleString("en-US"), "
"); var intensityInput = intensityRange.querySelector("input"); intensityInput.addEventListener("input", function () { var value = parseInt(intensityInput.value); intensityContainer.innerHTML = "Intensity : ".concat(value.toLocaleString("en-US"), ""); if (isAttractionForce) { interaction.options.g = -value / INTENSITY_DIVIDER; } else { interaction.options.g = value / INTENSITY_DIVIDER; } }); var distanceContainer = document.createElement("h4"); distanceContainer.classList.add("setting"); distanceContainer.innerHTML = "Distance : ".concat(DISTANCE_DEFAULT.toLocaleString("en-US"), ""); var distanceRange = document.createElement("div"); distanceRange.classList.add("range"); distanceRange.innerHTML = "".concat(DISTANCE_MIN.toLocaleString("en-US"), "
").concat(DISTANCE_MAX.toLocaleString("en-US"), "
"); var distanceInput = distanceRange.querySelector("input"); distanceInput.addEventListener("input", function () { var value = parseInt(distanceInput.value); distanceContainer.innerHTML = "Distance : ".concat(value.toLocaleString("en-US"), ""); interaction.options.distance = value; }); close.addEventListener("click", function () { interactions = interactions.filter(function (itn) { return itn !== interaction; }); container.removeChild(interactionContainer); }); interactionContainer.appendChild(colors); interactionContainer.appendChild(forceContainer); interactionContainer.appendChild(intensityContainer); interactionContainer.appendChild(intensityRange); interactionContainer.appendChild(distanceContainer); interactionContainer.appendChild(distanceRange); container.appendChild(interactionContainer); } 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; if (options === void 0) { options = {}; } var g = (_a = options.g) !== null && _a !== void 0 ? _a : 0.1; var distance = (_b = options.distance) !== null && _b !== void 0 ? _b : 100; 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 < distance) { var F = 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.01; a.y += a.vy * 0.01; } } } (_a = document.querySelector(".add.particle")) === null || _a === void 0 ? void 0 : _a.addEventListener("click", function () { var color = null; for (var c in colors) { if (!colors[c]) { color = c; break; } } if (color) addColor(color); }); (_b = document.querySelector(".add.interaction")) === null || _b === void 0 ? void 0 : _b.addEventListener("click", function () { if (interactions.length >= MAX_INTERACTION_NUMBER) return; var color1 = null; var color2 = null; for (var c in colors) { if (colors[c]) { color1 = c; break; } } if (!color1) return; for (var c in colors) { if (colors[c] && c !== color1) { color2 = c; break; } } if (!color2) color2 = color1; var group1 = colors[color1]; var group2 = colors[color2]; if (!group1 || !group2) return; var intensity = DEFAULT_INTENSITY; var distance = 100; var options = { distance: distance, g: intensity / INTENSITY_DIVIDER, }; var interaction = { group1: group1, group2: group2, options: options, }; addInteraction(interaction); }); (_c = document.querySelector(".play-pause")) === null || _c === void 0 ? void 0 : _c.addEventListener("click", function () { paused = !paused; var img = document.querySelector(".play-pause img"); img.src = paused ? "/assets/images/svg/play_arrow.svg" : "/assets/images/svg/pause.svg"; }); (_d = document.querySelector(".reset")) === null || _d === void 0 ? void 0 : _d.addEventListener("click", function () { reset(); }); (_e = document.querySelector(".save")) === null || _e === void 0 ? void 0 : _e.addEventListener("click", function () { var element = document.createElement("a"); element.style.display = "none"; element.download = "ps".concat(Date.now(), ".json"); element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(JSON.stringify([ interactions.map(function (itn) { return ({ group1: itn.group1[0].color, group2: itn.group2[0].color, options: itn.options, }); }), Object.entries(colors) .filter(function (_a) { var _ = _a[0], v = _a[1]; return v; }) .map(function (_a) { var k = _a[0], _ = _a[1]; return ({ color: k, number: colors[k].length, }); }), ]))); element.click(); element.remove(); }); (_f = document.querySelector(".load")) === null || _f === void 0 ? void 0 : _f.addEventListener("click", function () { var element = document.createElement("input"); element.style.display = "none"; element.type = "file"; element.accept = ".json"; element.addEventListener("change", function (e) { var file = e.target.files[0]; var reader = new FileReader(); reader.addEventListener("load", function (e) { var _a = JSON.parse(e.target.result), itn = _a[0], groups = _a[1]; interactions = []; particles = []; var particleContainer = document.querySelector(".particle-containers"); var interactionContainer = document.querySelector(".interaction-containers"); particleContainer.innerHTML = ""; interactionContainer.innerHTML = ""; for (var _i = 0, groups_1 = groups; _i < groups_1.length; _i++) { var group = groups_1[_i]; addColor(group.color, false); colors[group.color] = makeGroup(group.number, group.color, { radius: Particle.DEFAULT_RADIUS, }); } for (var _b = 0, itn_1 = itn; _b < itn_1.length; _b++) { var it = itn_1[_b]; var group1 = colors[it.group1]; var group2 = colors[it.group2]; if (!group1 || !group2) continue; addInteraction({ group1: group1, group2: group2, options: it.options, }); } }); reader.readAsText(file); }); element.click(); element.remove(); }); (_g = document.querySelector(".minimize")) === null || _g === void 0 ? void 0 : _g.addEventListener("click", function () { var gui = document.querySelector(".gui .content"); gui.classList.toggle("minimized"); }); window.addEventListener("resize", function () { canvas.width = window.innerWidth; canvas.height = window.innerHeight; reset(); }); window.addEventListener("click", function () { document.querySelectorAll(".color-list").forEach(function (colorList) { if (colorList.classList.contains("show")) { colorList.classList.remove("show"); } }); }); addColor("red"); addColor("green"); addInteraction({ group1: colors.red, group2: colors.green, options: { distance: DISTANCE_DEFAULT, g: -DEFAULT_INTENSITY / INTENSITY_DIVIDER, }, }); function animate() { if (!paused) { interactions.forEach(function (itn) { return interaction(itn.group1, itn.group2, itn.options); }); } ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "#000000"; ctx.fillRect(0, 0, canvas.width, canvas.height); particles.forEach(function (particle) { return particle.draw(ctx); }); return requestAnimationFrame(animate); } animate();