AL-S (обсуждение | вклад) (Полностью удалено содержимое страницы) Метки: очистка ручная отмена |
Perl (обсуждение | вклад) (! New style (js) try 1) |
||
(не показаны 3 промежуточные версии 1 участника) | |||
Строка 1: | Строка 1: | ||
(function() { | |||
'use strict'; | |||
// Проверяем, что мы не на мобильном устройстве (для производительности) | |||
var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); | |||
var isLowPerformance = navigator.hardwareConcurrency < 4; | |||
// Конфигурация частиц под тему сайта | |||
var themeColors = { | |||
primary: '#77c1d9', | |||
secondary: '#9dd7ea', | |||
accent: '#b8e6ff', | |||
background: '#1a1a1f' | |||
}; | |||
// Функция создания и настройки частиц | |||
function initParticleSystem() { | |||
// Проверяем, не создан ли уже контейнер | |||
if (document.getElementById('particles-js')) { | |||
return; | |||
} | |||
// Создаем стилизованный контейнер | |||
var particlesDiv = document.createElement('div'); | |||
particlesDiv.id = 'particles-js'; | |||
particlesDiv.setAttribute('aria-hidden', 'true'); // Для доступности | |||
// Вставляем после body, но перед основным контентом | |||
var mwBody = document.querySelector('.mw-body'); | |||
if (mwBody) { | |||
document.body.insertBefore(particlesDiv, mwBody); | |||
} else { | |||
document.body.appendChild(particlesDiv); | |||
} | |||
// Улучшенные стили с адаптивностью | |||
var particleStyles = document.createElement('style'); | |||
particleStyles.id = 'particles-styles'; | |||
particleStyles.innerHTML = ` | |||
#particles-js { | |||
position: fixed; | |||
top: 0; | |||
left: 0; | |||
width: 100vw; | |||
height: 100vh; | |||
z-index: -1; | |||
pointer-events: none; | |||
opacity: 0.8; | |||
transition: opacity 0.5s ease; | |||
} | |||
/* Уменьшаем эффект на маленьких экранах */ | |||
@media (max-width: 768px) { | |||
#particles-js { | |||
opacity: 0.3; | |||
} | |||
} | |||
/* Полностью отключаем на очень маленьких экранах */ | |||
@media (max-width: 480px) { | |||
#particles-js { | |||
display: none; | |||
} | |||
} | |||
/* Уменьшаем эффект при предпочтении пользователя */ | |||
@media (prefers-reduced-motion: reduce) { | |||
#particles-js { | |||
opacity: 0.2; | |||
} | |||
} | |||
/* Адаптация под высокий DPI */ | |||
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { | |||
#particles-js canvas { | |||
image-rendering: crisp-edges; | |||
} | |||
} | |||
/* Плавное появление частиц */ | |||
#particles-js.loaded { | |||
animation: particlesFadeIn 2s ease-in; | |||
} | |||
@keyframes particlesFadeIn { | |||
from { opacity: 0; } | |||
to { opacity: 0.8; } | |||
} | |||
`; | |||
document.head.appendChild(particleStyles); | |||
// Загружаем библиотеку с обработкой ошибок | |||
loadParticlesLibrary(); | |||
} | |||
// Улучшенная функция загрузки библиотеки | |||
function loadParticlesLibrary() { | |||
// Проверяем, не загружена ли уже библиотека | |||
if (window.particlesJS) { | |||
initParticles(); | |||
return; | |||
} | |||
var script = document.createElement('script'); | |||
script.src = 'https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js'; | |||
script.async = true; | |||
script.defer = true; | |||
script.onload = function() { | |||
console.log('Particles.js загружена успешно'); | |||
initParticles(); | |||
}; | |||
script.onerror = function() { | |||
console.warn('Не удалось загрузить particles.js'); | |||
// Можно добавить fallback эффект | |||
addFallbackEffect(); | |||
}; | |||
document.head.appendChild(script); | |||
} | |||
// Основная функция инициализации частиц | |||
function initParticles() { | |||
var particleCount = getOptimalParticleCount(); | |||
var config = { | |||
particles: { | |||
number: { | |||
value: particleCount, | |||
density: { | |||
enable: true, | |||
value_area: 1000 | |||
} | |||
}, | |||
color: { | |||
value: [themeColors.primary, themeColors.secondary, themeColors.accent] | |||
}, | |||
shape: { | |||
type: ['circle', 'triangle'], | |||
stroke: { | |||
width: 0, | |||
color: themeColors.primary | |||
}, | |||
polygon: { | |||
nb_sides: 6 | |||
} | |||
}, | |||
opacity: { | |||
value: 0.6, | |||
random: true, | |||
anim: { | |||
enable: true, | |||
speed: 0.8, | |||
opacity_min: 0.1, | |||
sync: false | |||
} | |||
}, | |||
size: { | |||
value: 4, | |||
random: true, | |||
anim: { | |||
enable: true, | |||
speed: 2, | |||
size_min: 0.5, | |||
sync: false | |||
} | |||
}, | |||
line_linked: { | |||
enable: true, | |||
distance: 180, | |||
color: themeColors.primary, | |||
opacity: 0.3, | |||
width: 1.5 | |||
}, | |||
move: { | |||
enable: true, | |||
speed: isMobile ? 2 : 4, | |||
direction: 'none', | |||
random: true, | |||
straight: false, | |||
out_mode: 'out', | |||
bounce: false, | |||
attract: { | |||
enable: true, | |||
rotateX: 600, | |||
rotateY: 1200 | |||
} | |||
} | |||
}, | |||
interactivity: { | |||
detect_on: 'window', | |||
events: { | |||
onhover: { | |||
enable: !isMobile, | |||
mode: 'grab' | |||
}, | |||
onclick: { | |||
enable: true, | |||
mode: 'push' | |||
}, | |||
resize: true | |||
}, | |||
modes: { | |||
grab: { | |||
distance: 200, | |||
line_linked: { | |||
opacity: 0.8 | |||
} | |||
}, | |||
bubble: { | |||
distance: 300, | |||
size: 8, | |||
duration: 2, | |||
opacity: 0.8, | |||
speed: 3 | |||
}, | |||
repulse: { | |||
distance: 150, | |||
duration: 0.4 | |||
}, | |||
push: { | |||
particles_nb: 3 | |||
}, | |||
remove: { | |||
particles_nb: 2 | |||
} | |||
} | |||
}, | |||
retina_detect: true | |||
}; | |||
// Инициализируем частицы с callback | |||
particlesJS('particles-js', config, function() { | |||
console.log('Particles.js: система частиц активирована'); | |||
document.getElementById('particles-js').classList.add('loaded'); | |||
}); | |||
// Добавляем контроли производительности | |||
addPerformanceControls(); | |||
} | |||
// Определяем оптимальное количество частиц | |||
function getOptimalParticleCount() { | |||
var baseCount = 60; | |||
if (isMobile) return Math.floor(baseCount * 0.5); | |||
if (isLowPerformance) return Math.floor(baseCount * 0.7); | |||
if (window.innerWidth < 1200) return Math.floor(baseCount * 0.8); | |||
return baseCount; | |||
} | |||
// Добавляем контроли производительности | |||
function addPerformanceControls() { | |||
var particleContainer = document.getElementById('particles-js'); | |||
if (!particleContainer) return; | |||
// Уменьшаем интенсивность при переключении вкладок | |||
document.addEventListener('visibilitychange', function() { | |||
if (document.hidden) { | |||
particleContainer.style.opacity = '0.1'; | |||
} else { | |||
particleContainer.style.opacity = '0.8'; | |||
} | |||
}); | |||
// Адаптируем к изменению размера окна | |||
var resizeTimeout; | |||
window.addEventListener('resize', function() { | |||
clearTimeout(resizeTimeout); | |||
resizeTimeout = setTimeout(function() { | |||
if (window.pJSDom && window.pJSDom[0]) { | |||
window.pJSDom[0].pJS.fn.particlesRefresh(); | |||
} | |||
}, 300); | |||
}); | |||
} | |||
// Fallback эффект при неудачной загрузке | |||
function addFallbackEffect() { | |||
var particleContainer = document.getElementById('particles-js'); | |||
if (!particleContainer) return; | |||
particleContainer.innerHTML = ` | |||
<div style=" | |||
position: absolute; | |||
top: 0; | |||
left: 0; | |||
width: 100%; | |||
height: 100%; | |||
background: radial-gradient(ellipse at center, | |||
rgba(119, 193, 217, 0.1) 0%, | |||
rgba(26, 26, 31, 0.8) 70%); | |||
animation: pulseGlow 4s ease-in-out infinite; | |||
"></div> | |||
`; | |||
var fallbackStyle = document.createElement('style'); | |||
fallbackStyle.innerHTML = ` | |||
@keyframes pulseGlow { | |||
0%, 100% { opacity: 0.3; } | |||
50% { opacity: 0.6; } | |||
} | |||
`; | |||
document.head.appendChild(fallbackStyle); | |||
} | |||
// Функция очистки (для отладки) | |||
function cleanupParticles() { | |||
var container = document.getElementById('particles-js'); | |||
var styles = document.getElementById('particles-styles'); | |||
if (container) container.remove(); | |||
if (styles) styles.remove(); | |||
if (window.pJSDom) { | |||
window.pJSDom = []; | |||
} | |||
} | |||
// Экспорт функций для отладки | |||
window.particleSystem = { | |||
init: initParticleSystem, | |||
cleanup: cleanupParticles, | |||
config: themeColors | |||
}; | |||
// Инициализация после загрузки MediaWiki | |||
if (document.readyState === 'loading') { | |||
document.addEventListener('DOMContentLoaded', initParticleSystem); | |||
} else { | |||
initParticleSystem(); | |||
} | |||
})(); | |||
// Дополнительные улучшения для интеграции с темой | |||
mw.hook('wikipage.content').add(function($content) { | |||
// Подстраиваем частицы под контент страницы | |||
setTimeout(function() { | |||
if (window.pJSDom && window.pJSDom[0]) { | |||
window.pJSDom[0].pJS.fn.particlesRefresh(); | |||
} | |||
}, 500); | |||
}); |
Текущая версия от 01:51, 1 августа 2025
(function() {
'use strict';
// Проверяем, что мы не на мобильном устройстве (для производительности)
var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
var isLowPerformance = navigator.hardwareConcurrency < 4;
// Конфигурация частиц под тему сайта
var themeColors = {
primary: '#77c1d9',
secondary: '#9dd7ea',
accent: '#b8e6ff',
background: '#1a1a1f'
};
// Функция создания и настройки частиц
function initParticleSystem() {
// Проверяем, не создан ли уже контейнер
if (document.getElementById('particles-js')) {
return;
}
// Создаем стилизованный контейнер
var particlesDiv = document.createElement('div');
particlesDiv.id = 'particles-js';
particlesDiv.setAttribute('aria-hidden', 'true'); // Для доступности
// Вставляем после body, но перед основным контентом
var mwBody = document.querySelector('.mw-body');
if (mwBody) {
document.body.insertBefore(particlesDiv, mwBody);
} else {
document.body.appendChild(particlesDiv);
}
// Улучшенные стили с адаптивностью
var particleStyles = document.createElement('style');
particleStyles.id = 'particles-styles';
particleStyles.innerHTML = `
#particles-js {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -1;
pointer-events: none;
opacity: 0.8;
transition: opacity 0.5s ease;
}
/* Уменьшаем эффект на маленьких экранах */
@media (max-width: 768px) {
#particles-js {
opacity: 0.3;
}
}
/* Полностью отключаем на очень маленьких экранах */
@media (max-width: 480px) {
#particles-js {
display: none;
}
}
/* Уменьшаем эффект при предпочтении пользователя */
@media (prefers-reduced-motion: reduce) {
#particles-js {
opacity: 0.2;
}
}
/* Адаптация под высокий DPI */
@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
#particles-js canvas {
image-rendering: crisp-edges;
}
}
/* Плавное появление частиц */
#particles-js.loaded {
animation: particlesFadeIn 2s ease-in;
}
@keyframes particlesFadeIn {
from { opacity: 0; }
to { opacity: 0.8; }
}
`;
document.head.appendChild(particleStyles);
// Загружаем библиотеку с обработкой ошибок
loadParticlesLibrary();
}
// Улучшенная функция загрузки библиотеки
function loadParticlesLibrary() {
// Проверяем, не загружена ли уже библиотека
if (window.particlesJS) {
initParticles();
return;
}
var script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js';
script.async = true;
script.defer = true;
script.onload = function() {
console.log('Particles.js загружена успешно');
initParticles();
};
script.onerror = function() {
console.warn('Не удалось загрузить particles.js');
// Можно добавить fallback эффект
addFallbackEffect();
};
document.head.appendChild(script);
}
// Основная функция инициализации частиц
function initParticles() {
var particleCount = getOptimalParticleCount();
var config = {
particles: {
number: {
value: particleCount,
density: {
enable: true,
value_area: 1000
}
},
color: {
value: [themeColors.primary, themeColors.secondary, themeColors.accent]
},
shape: {
type: ['circle', 'triangle'],
stroke: {
width: 0,
color: themeColors.primary
},
polygon: {
nb_sides: 6
}
},
opacity: {
value: 0.6,
random: true,
anim: {
enable: true,
speed: 0.8,
opacity_min: 0.1,
sync: false
}
},
size: {
value: 4,
random: true,
anim: {
enable: true,
speed: 2,
size_min: 0.5,
sync: false
}
},
line_linked: {
enable: true,
distance: 180,
color: themeColors.primary,
opacity: 0.3,
width: 1.5
},
move: {
enable: true,
speed: isMobile ? 2 : 4,
direction: 'none',
random: true,
straight: false,
out_mode: 'out',
bounce: false,
attract: {
enable: true,
rotateX: 600,
rotateY: 1200
}
}
},
interactivity: {
detect_on: 'window',
events: {
onhover: {
enable: !isMobile,
mode: 'grab'
},
onclick: {
enable: true,
mode: 'push'
},
resize: true
},
modes: {
grab: {
distance: 200,
line_linked: {
opacity: 0.8
}
},
bubble: {
distance: 300,
size: 8,
duration: 2,
opacity: 0.8,
speed: 3
},
repulse: {
distance: 150,
duration: 0.4
},
push: {
particles_nb: 3
},
remove: {
particles_nb: 2
}
}
},
retina_detect: true
};
// Инициализируем частицы с callback
particlesJS('particles-js', config, function() {
console.log('Particles.js: система частиц активирована');
document.getElementById('particles-js').classList.add('loaded');
});
// Добавляем контроли производительности
addPerformanceControls();
}
// Определяем оптимальное количество частиц
function getOptimalParticleCount() {
var baseCount = 60;
if (isMobile) return Math.floor(baseCount * 0.5);
if (isLowPerformance) return Math.floor(baseCount * 0.7);
if (window.innerWidth < 1200) return Math.floor(baseCount * 0.8);
return baseCount;
}
// Добавляем контроли производительности
function addPerformanceControls() {
var particleContainer = document.getElementById('particles-js');
if (!particleContainer) return;
// Уменьшаем интенсивность при переключении вкладок
document.addEventListener('visibilitychange', function() {
if (document.hidden) {
particleContainer.style.opacity = '0.1';
} else {
particleContainer.style.opacity = '0.8';
}
});
// Адаптируем к изменению размера окна
var resizeTimeout;
window.addEventListener('resize', function() {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(function() {
if (window.pJSDom && window.pJSDom[0]) {
window.pJSDom[0].pJS.fn.particlesRefresh();
}
}, 300);
});
}
// Fallback эффект при неудачной загрузке
function addFallbackEffect() {
var particleContainer = document.getElementById('particles-js');
if (!particleContainer) return;
particleContainer.innerHTML = `
<div style="
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(ellipse at center,
rgba(119, 193, 217, 0.1) 0%,
rgba(26, 26, 31, 0.8) 70%);
animation: pulseGlow 4s ease-in-out infinite;
"></div>
`;
var fallbackStyle = document.createElement('style');
fallbackStyle.innerHTML = `
@keyframes pulseGlow {
0%, 100% { opacity: 0.3; }
50% { opacity: 0.6; }
}
`;
document.head.appendChild(fallbackStyle);
}
// Функция очистки (для отладки)
function cleanupParticles() {
var container = document.getElementById('particles-js');
var styles = document.getElementById('particles-styles');
if (container) container.remove();
if (styles) styles.remove();
if (window.pJSDom) {
window.pJSDom = [];
}
}
// Экспорт функций для отладки
window.particleSystem = {
init: initParticleSystem,
cleanup: cleanupParticles,
config: themeColors
};
// Инициализация после загрузки MediaWiki
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initParticleSystem);
} else {
initParticleSystem();
}
})();
// Дополнительные улучшения для интеграции с темой
mw.hook('wikipage.content').add(function($content) {
// Подстраиваем частицы под контент страницы
setTimeout(function() {
if (window.pJSDom && window.pJSDom[0]) {
window.pJSDom[0].pJS.fn.particlesRefresh();
}
}, 500);
});