unified: Phantom Protocol 2025 complete archive integration
This commit is contained in:
237
website/js/background.js
Normal file
237
website/js/background.js
Normal file
@@ -0,0 +1,237 @@
|
||||
/* ==========================================
|
||||
Phantom Protocol - Advanced Background Animation
|
||||
DHT Network visualization with nodes and connections
|
||||
Based on Hero section animation
|
||||
© NeroWorld AI, 2025
|
||||
========================================== */
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// Конфигурация
|
||||
const config = {
|
||||
nodeCount: 60, // Количество узлов DHT
|
||||
connectionDistance: 180, // Расстояние для связей
|
||||
nodeSpeedMin: 0.2, // Минимальная скорость
|
||||
nodeSpeedMax: 0.8, // Максимальная скорость
|
||||
nodeRadiusMin: 1.5, // Минимальный размер узла
|
||||
nodeRadiusMax: 3, // Максимальный размер узла
|
||||
colors: {
|
||||
node: 'rgba(0, 240, 255, ', // Цвет узлов (cyan) + opacity
|
||||
connection: 'rgba(122, 62, 255, ', // Цвет связей (purple) + opacity
|
||||
glow: 'rgba(0, 240, 255, 0.5)' // Цвет свечения
|
||||
}
|
||||
};
|
||||
|
||||
// Класс узла DHT сети
|
||||
class DHTNode {
|
||||
constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
this.reset();
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.x = Math.random() * this.canvas.width;
|
||||
this.y = Math.random() * this.canvas.height;
|
||||
this.vx = (Math.random() - 0.5) * (config.nodeSpeedMin + Math.random() * (config.nodeSpeedMax - config.nodeSpeedMin));
|
||||
this.vy = (Math.random() - 0.5) * (config.nodeSpeedMin + Math.random() * (config.nodeSpeedMax - config.nodeSpeedMin));
|
||||
this.radius = config.nodeRadiusMin + Math.random() * (config.nodeRadiusMax - config.nodeRadiusMin);
|
||||
this.opacity = Math.random() * 0.5 + 0.5; // 0.5 - 1.0
|
||||
}
|
||||
|
||||
update() {
|
||||
this.x += this.vx;
|
||||
this.y += this.vy;
|
||||
|
||||
// Отскок от границ
|
||||
if (this.x < 0 || this.x > this.canvas.width) {
|
||||
this.vx *= -1;
|
||||
this.x = Math.max(0, Math.min(this.canvas.width, this.x));
|
||||
}
|
||||
if (this.y < 0 || this.y > this.canvas.height) {
|
||||
this.vy *= -1;
|
||||
this.y = Math.max(0, Math.min(this.canvas.height, this.y));
|
||||
}
|
||||
}
|
||||
|
||||
draw(ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
|
||||
ctx.fillStyle = config.colors.node + this.opacity + ')';
|
||||
ctx.fill();
|
||||
|
||||
// Добавляем свечение для больших узлов
|
||||
if (this.radius > 2) {
|
||||
ctx.shadowBlur = 15;
|
||||
ctx.shadowColor = config.colors.glow;
|
||||
ctx.fill();
|
||||
ctx.shadowBlur = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Класс анимации DHT сети
|
||||
class DHTNetworkAnimation {
|
||||
constructor(canvasId) {
|
||||
this.canvas = document.getElementById(canvasId);
|
||||
if (!this.canvas) {
|
||||
console.warn('Canvas element not found:', canvasId);
|
||||
return;
|
||||
}
|
||||
|
||||
this.ctx = this.canvas.getContext('2d');
|
||||
this.nodes = [];
|
||||
this.animationId = null;
|
||||
this.resizeTimeout = null;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
// Установка размера canvas
|
||||
this.resize();
|
||||
|
||||
// Создание узлов DHT
|
||||
for (let i = 0; i < config.nodeCount; i++) {
|
||||
this.nodes.push(new DHTNode(this.canvas));
|
||||
}
|
||||
|
||||
// Обработчик изменения размера окна с throttling
|
||||
window.addEventListener('resize', () => {
|
||||
if (this.resizeTimeout) clearTimeout(this.resizeTimeout);
|
||||
this.resizeTimeout = setTimeout(() => this.resize(), 150);
|
||||
});
|
||||
|
||||
// Запуск анимации
|
||||
this.animate();
|
||||
}
|
||||
|
||||
resize() {
|
||||
if (!this.canvas) return;
|
||||
|
||||
const newWidth = window.innerWidth;
|
||||
const newHeight = Math.max(
|
||||
document.documentElement.scrollHeight,
|
||||
document.body.scrollHeight,
|
||||
document.documentElement.clientHeight,
|
||||
window.innerHeight
|
||||
);
|
||||
|
||||
// Обновляем только если размер изменился
|
||||
if (this.canvas.width !== newWidth || this.canvas.height !== newHeight) {
|
||||
this.canvas.width = newWidth;
|
||||
this.canvas.height = newHeight;
|
||||
|
||||
// Переинициализируем узлы при большом изменении размера
|
||||
if (Math.abs(this.canvas.width - newWidth) > 100) {
|
||||
this.nodes.forEach(node => node.reset());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawConnections() {
|
||||
const { connectionDistance, colors } = config;
|
||||
|
||||
for (let i = 0; i < this.nodes.length; i++) {
|
||||
for (let j = i + 1; j < this.nodes.length; j++) {
|
||||
const dx = this.nodes[i].x - this.nodes[j].x;
|
||||
const dy = this.nodes[i].y - this.nodes[j].y;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
if (distance < connectionDistance) {
|
||||
// Opacity зависит от расстояния (ближе = ярче)
|
||||
const opacity = (1 - distance / connectionDistance) * 0.4;
|
||||
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(this.nodes[i].x, this.nodes[i].y);
|
||||
this.ctx.lineTo(this.nodes[j].x, this.nodes[j].y);
|
||||
this.ctx.strokeStyle = colors.connection + opacity + ')';
|
||||
this.ctx.lineWidth = 1;
|
||||
this.ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
animate() {
|
||||
if (!this.canvas || !this.ctx) return;
|
||||
|
||||
// Очистка canvas
|
||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
|
||||
// Рисуем связи первыми (за узлами)
|
||||
this.drawConnections();
|
||||
|
||||
// Обновление и отрисовка узлов
|
||||
this.nodes.forEach(node => {
|
||||
node.update();
|
||||
node.draw(this.ctx);
|
||||
});
|
||||
|
||||
// Следующий кадр
|
||||
this.animationId = requestAnimationFrame(() => this.animate());
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this.animationId) {
|
||||
cancelAnimationFrame(this.animationId);
|
||||
this.animationId = null;
|
||||
}
|
||||
if (this.resizeTimeout) {
|
||||
clearTimeout(this.resizeTimeout);
|
||||
}
|
||||
this.nodes = [];
|
||||
}
|
||||
}
|
||||
|
||||
// Автоматическая инициализация при загрузке
|
||||
function initBackground() {
|
||||
// Проверяем что DOM загружен
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', startAnimation);
|
||||
} else {
|
||||
startAnimation();
|
||||
}
|
||||
|
||||
function startAnimation() {
|
||||
// Ждем полной загрузки страницы
|
||||
if (document.readyState === 'complete') {
|
||||
createAnimation();
|
||||
} else {
|
||||
window.addEventListener('load', createAnimation);
|
||||
}
|
||||
}
|
||||
|
||||
function createAnimation() {
|
||||
setTimeout(() => {
|
||||
// Создаем анимацию
|
||||
window.phantomBackground = new DHTNetworkAnimation('phantomBackground');
|
||||
|
||||
// Отслеживание изменений DOM (с throttling)
|
||||
if (window.phantomBackground) {
|
||||
let mutationTimeout;
|
||||
const observer = new MutationObserver(() => {
|
||||
if (mutationTimeout) clearTimeout(mutationTimeout);
|
||||
mutationTimeout = setTimeout(() => {
|
||||
if (window.phantomBackground && typeof window.phantomBackground.resize === 'function') {
|
||||
window.phantomBackground.resize();
|
||||
}
|
||||
}, 1000); // Задержка 1 секунда для стабильности
|
||||
});
|
||||
|
||||
// Наблюдаем за изменениями структуры страницы
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: false
|
||||
});
|
||||
}
|
||||
|
||||
console.log('✨ DHT Network Background initialized');
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
|
||||
// Запуск
|
||||
initBackground();
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user