Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion css/particle-effects.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* Particle effects for visualization background */

.particles-container {
#particle-canvas {
position: fixed;
top: 0;
left: 0;
Expand Down
91 changes: 2 additions & 89 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,9 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<!-- Add compatibility script first to handle browser differences -->
<script src="js/browser-compatibility.js"></script>
<!-- Add particles.js library -->
<script src="https://cdn.jsdelivr.net/npm/particles.js@2.0.0/particles.min.js"></script>
</head>
<body>
<!-- Add particles container at the beginning of body -->
<div id="particles-js"></div>

<canvas id="particle-canvas"></canvas>
<div class="container">
<h1>Advanced Merge Sort Visualization</h1>

Expand Down Expand Up @@ -134,6 +130,7 @@ <h3>Made by Nikhil Kumar</h3>
<script src="js/mergesort-bridge.js"></script>
<script src="js/mergesort-algorithm.js"></script>
<script src="js/particles-config.js"></script>
<script src="js/particle-renderer.js"></script>

<!-- Button click handlers -->
<script>
Expand All @@ -143,91 +140,7 @@ <h3>Made by Nikhil Kumar</h3>
document.getElementById('startSortBtn').addEventListener('click', startSort);
document.getElementById('resetBtn').addEventListener('click', resetVisualization);
document.getElementById('pauseResumeBtn').addEventListener('click', togglePause);

// Initialize particles with our enhanced configuration
setTimeout(function() {
// Initialize particles with WebGL fallback
initializeParticlesWithFallback();

// Set up additional interactive features after a short delay
setTimeout(() => {
// Fix mouse interaction explicitly
if (window.pJSDom && window.pJSDom[0] && window.pJSDom[0].pJS) {
fixMouseInteraction(window.pJSDom[0].pJS);
}

// Set up dynamic color changes that respond to mouse proximity
setupDynamicColors();

// Set up activity tracking
setupActivityTracking();

// Set up visibility optimization
window.addEventListener("scroll", checkParticlesVisibility);
checkParticlesVisibility();

// Set up tab visibility handling
document.addEventListener("visibilitychange", handleVisibilityChange);

console.log('Enhanced particles initialized with interactive features');

// Add a hint for users about the interactive particles
showInteractionHint();
}, 500);
}, 100);
});

// Show a hint to help users discover the particle interaction
function showInteractionHint() {
const hint = document.createElement('div');
hint.textContent = "Move your cursor to interact with particles";
hint.style.position = 'fixed';
hint.style.bottom = '30px';
hint.style.left = '50%';
hint.style.transform = 'translateX(-50%)';
hint.style.background = 'rgba(0,0,0,0.8)';
hint.style.color = 'white';
hint.style.padding = '10px 20px';
hint.style.borderRadius = '20px';
hint.style.fontFamily = 'Arial, sans-serif';
hint.style.fontSize = '14px';
hint.style.zIndex = '1000';
hint.style.opacity = '0';
hint.style.transition = 'opacity 0.5s ease';

document.body.appendChild(hint);

// Show the hint after a short delay
setTimeout(() => {
hint.style.opacity = '1';

// Hide after a few seconds
setTimeout(() => {
hint.style.opacity = '0';

// Remove from DOM after fade out
setTimeout(() => hint.remove(), 500);
}, 5000);
}, 2000);
}

// Visibility change handler extracted for cleaner code
function handleVisibilityChange() {
if (!window.pJSDom || !window.pJSDom[0] || !window.pJSDom[0].pJS) return;

const pJS = window.pJSDom[0].pJS;
if (document.hidden) {
if (pJS.fn.pause) {
pJS.fn.pause();
pJS._tabHidden = true;
}
} else if (pJS._tabHidden) {
if (pJS.fn.play) {
pJS.fn.play();
pJS._tabHidden = false;
}
}
}
</script>
</body>
</html>
3 changes: 3 additions & 0 deletions js/mergesort-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Initialize array with random values and visualize bars with labels
function initArray() {
array = [];
bars = [];
visualization.innerHTML = '';
const arraySize = parseInt(arraySizeControl.value);

Expand All @@ -26,6 +27,7 @@ function createBar(value) {
label.textContent = value;
bar.appendChild(label);
visualization.appendChild(bar);
bars.push(bar);

// Animate the bar height after adding to DOM
setTimeout(() => {
Expand Down Expand Up @@ -57,6 +59,7 @@ function logStep(message, phase = '') {
// Reset visualization with proper cleanup
function resetVisualization() {
array = [];
bars = [];
visualization.innerHTML = '';
stepsOutput.innerHTML = '';
divideTreeContainer.innerHTML = '';
Expand Down
30 changes: 15 additions & 15 deletions js/mergesort-init.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

// State variables for the visualization
let array = [];
let bars = [];
let animationSpeed = 300;
let isPaused = false;
let pausePromiseResolve = null;
Expand Down Expand Up @@ -52,24 +53,23 @@ function setupScrollHandlers() {

// Enhanced window resize handler
function setupResizeHandler() {
let resizeTimeout = null;
window.addEventListener('resize', () => {
if (resizeTimeout) clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
// Update layout based on new viewport size
updateLayoutForViewport();

// Enhance tree layout
enhanceTreeLayout();

// Update connections after layout changes
setTimeout(() => {
updateAllConnections();
}, 100);
}, 100);
var lastResize = 0;
window.addEventListener('resize', function(){
var now = Date.now();
if(now - lastResize > 100){
lastResize = now;
requestAnimationFrame(applyResize);
}
});
}

function applyResize(){
// current resize logic
updateLayoutForViewport();
enhanceTreeLayout();
updateAllConnections();
}

// Setup event listeners for controls
function setupEventListeners() {
// Update speed value display and variable when slider changes
Expand Down
44 changes: 29 additions & 15 deletions js/mergesort-visualization.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,32 @@
* Handles rendering, animations, and UI updates.
*/

var pendingChanges = [];

function updateBar(idx, value){
pendingChanges.push({i: idx, value: value});
}

function applyBarChanges(){
for(var k = 0; k < pendingChanges.length; k++){
var c = pendingChanges[k];
bars[c.i].style.height = c.value + "px";
}
pendingChanges = [];
}

// main draw loop
function draw(){
applyBarChanges();
requestAnimationFrame(draw);
}

requestAnimationFrame(draw);

// Update visualization on the page with highlighting
async function updateVisualization(arr, highlightIndices = []) {
try {
// Batch update for better performance
const fragment = document.createDocumentFragment();

if (!Array.isArray(arr)) {
console.error("Invalid array provided to updateVisualization");
Expand All @@ -17,25 +38,18 @@ async function updateVisualization(arr, highlightIndices = []) {
// Determine if we're on mobile for bar sizing
const isMobile = window.innerWidth <= 480;

arr.forEach((val, idx) => {
let bar = document.createElement('div');
bar.className = 'bar';
bars.forEach((bar, idx) => {
if (highlightIndices.includes(idx)) {
bar.classList.add('comparing');
} else {
bar.classList.remove('comparing');
}

// Adjust bar height for mobile if needed
bar.style.height = (val * (isMobile ? 1.5 : 2)) + 'px';

let label = document.createElement('span');
label.className = 'barLabel';
label.textContent = val;
bar.appendChild(label);
fragment.appendChild(bar);
});

arr.forEach((val, idx) => {
updateBar(idx, (val * (isMobile ? 1.5 : 2)));
});

visualization.innerHTML = '';
visualization.appendChild(fragment);
await sleep(animationSpeed);
} catch (error) {
console.error("Error in updateVisualization:", error);
Expand Down
41 changes: 41 additions & 0 deletions js/particle-renderer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const canvas = document.getElementById('particle-canvas');
const ctx = canvas.getContext('2d');

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

function initParticles() {
for (let i = 0; i < 50; i++) {
addParticle({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
vx: (Math.random() - 0.5) * 2,
vy: (Math.random() - 0.5) * 2
});
}
}

function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);

for (const particle of particles) {
ctx.beginPath();
ctx.arc(particle.x, particle.y, 2, 0, 2 * Math.PI);
ctx.fillStyle = 'white';
ctx.fill();
}
}

function gameLoop() {
updateParticles();
render();
requestAnimationFrame(gameLoop);
}

window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
});

initParticles();
gameLoop();
Loading