Jump to content

MediaWiki:Common.js: Difference between revisions

The comprehensive free global encyclopedia of CEOs, corporate leadership, and business excellence
Pure JavaScript 3D tag cloud with extensive logging and multiple initialization methods
Added polling mechanism to wait for canvas element (fixes timing issue)
Line 46: Line 46:


/**
/**
  * Simple 3D Rotating Tag Cloud - Pure JavaScript - No Dependencies
  * Simple 3D Rotating Tag Cloud - With Polling for Canvas Element
  */
  */
function initCEOTagCloud() {
(function() {
     'use strict';
     'use strict';
      
      
Line 63: Line 63:
     }
     }
      
      
     var canvas = document.getElementById('tagcanvas');
     var attempts = 0;
     if (!canvas) {
     var maxAttempts = 50; // Try for 5 seconds (50 * 100ms)
        console.log('[TagCloud] Canvas element not found');
        return;
    }
      
      
     console.log('[TagCloud] Canvas found, initializing...');
     function tryInitialize() {
   
        attempts++;
    // Hide the fallback list
       
    var ul = canvas.querySelector('ul');
        var canvas = document.getElementById('tagcanvas');
    if (ul) {
        if (!canvas) {
        ul.style.display = 'none';
            if (attempts < maxAttempts) {
        console.log('[TagCloud] Fallback list hidden');
                console.log('[TagCloud] Canvas not found yet, retrying... (attempt ' + attempts + '/' + maxAttempts + ')');
    }
                setTimeout(tryInitialize, 100);
   
            } else {
    var ctx = canvas.getContext('2d');
                console.error('[TagCloud] Canvas element not found after ' + maxAttempts + ' attempts. Giving up.');
    if (!ctx) {
            }
        console.error('[TagCloud] Could not get 2D context');
            return;
        return;
        }
    }
       
   
        console.log('[TagCloud] Canvas found after ' + attempts + ' attempts! Initializing...');
    var width = canvas.width;
          
    var height = canvas.height;
         // Hide the fallback list
   
         var ul = canvas.querySelector('ul');
    console.log('[TagCloud] Canvas size:', width, 'x', height);
         if (ul) {
   
            ul.style.display = 'none';
    // Tags configuration
            console.log('[TagCloud] Fallback list hidden');
    var tags = [
         }
         { text: 'Satya Nadella', url: '/wiki/Satya_Nadella', size: 24 },
         { text: 'Tim Cook', url: '/wiki/Tim_Cook', size: 22 },
        { text: 'Elon Musk', url: '/wiki/Elon_Musk', size: 26 },
         { text: 'Mark Zuckerberg', url: '/wiki/Mark_Zuckerberg', size: 20 },
        { text: 'Sundar Pichai', url: '/wiki/Sundar_Pichai', size: 20 },
        { text: 'Andy Jassy', url: '/wiki/Andy_Jassy', size: 18 },
        { text: 'Jensen Huang', url: '/wiki/Jensen_Huang', size: 22 },
        { text: 'Lisa Su', url: '/wiki/Lisa_Su', size: 18 },
        { text: 'Mary Barra', url: '/wiki/Mary_Barra', size: 18 },
        { text: 'Jamie Dimon', url: '/wiki/Jamie_Dimon', size: 18 },
        { text: 'Microsoft', url: '/wiki/Microsoft', size: 16 },
        { text: 'Apple', url: '/wiki/Apple_Inc.', size: 16 },
        { text: 'Amazon', url: '/wiki/Amazon', size: 16 },
        { text: 'Google', url: '/wiki/Google', size: 16 },
        { text: 'Tesla', url: '/wiki/Tesla', size: 16 },
        { text: 'Leadership', url: '/wiki/Category:Chief_executive_officers', size: 14 },
        { text: 'Innovation', url: '/wiki/Category:Business_strategies', size: 14 },
        { text: 'Technology', url: '/wiki/Category:Companies', size: 14 },
        { text: 'Strategy', url: '/wiki/Category:Business_strategies', size: 14 },
        { text: 'Cloud Computing', url: '/wiki/Category:Industry_analysis', size: 14 }
    ];
   
    // Initialize 3D positions
    var radius = 180;
    var dtr = Math.PI / 180;
    var mcList = [];
    var lasta = 1;
    var lastb = 1;
    var tspeed = 0.5;
    var size = 250;
    var mouseX = 0;
    var mouseY = 0;
    var active = false;
   
    // Build tag objects
    for (var i = 0; i < tags.length; i++) {
        var oTag = {};
         oTag.offsetWidth = tags[i].size * 5;
        oTag.offsetHeight = tags[i].size;
        oTag.text = tags[i].text;
        oTag.url = tags[i].url;
        oTag.size = tags[i].size;
        mcList.push(oTag);
    }
   
    var sa, ca, sb, cb, sc, cc;
   
    function sineCosine(a, b, c) {
        sa = Math.sin(a * dtr);
        ca = Math.cos(a * dtr);
        sb = Math.sin(b * dtr);
        cb = Math.cos(b * dtr);
        sc = Math.sin(c * dtr);
         cc = Math.cos(c * dtr);
    }
   
    function positionAll() {
        var phi = 0;
        var theta = 0;
        var max = mcList.length;
          
          
         for (var i = 0; i < max; i++) {
         var ctx = canvas.getContext('2d');
            phi = Math.acos(-1 + (2 * i + 1) / max);
        if (!ctx) {
            theta = Math.sqrt(max * Math.PI) * phi;
             console.error('[TagCloud] Could not get 2D context');
              
             return;
            mcList[i].cx = radius * Math.cos(theta) * Math.sin(phi);
            mcList[i].cy = radius * Math.sin(theta) * Math.sin(phi);
             mcList[i].cz = radius * Math.cos(phi);
         }
         }
    }
   
    function doPosition() {
        ctx.clearRect(0, 0, width, height);
          
          
         for (var i = 0; i < mcList.length; i++) {
         var width = canvas.width;
            var tag = mcList[i];
        var height = canvas.height;
            var x = tag.x + width / 2;
       
             var y = tag.y + height / 2;
        console.log('[TagCloud] Canvas size:', width, 'x', height);
              
       
             var alpha = Math.max(0.2, Math.min(1, tag.alpha));
        // Tags configuration
             var fontSize = Math.max(10, tag.size * tag.scale);
        var tags = [
              
            { text: 'Satya Nadella', url: '/wiki/Satya_Nadella', size: 24 },
             ctx.save();
            { text: 'Tim Cook', url: '/wiki/Tim_Cook', size: 22 },
             ctx.font = fontSize + 'px sans-serif';
            { text: 'Elon Musk', url: '/wiki/Elon_Musk', size: 26 },
             ctx.fillStyle = 'rgba(255, 255, 255, ' + alpha + ')';
            { text: 'Mark Zuckerberg', url: '/wiki/Mark_Zuckerberg', size: 20 },
             ctx.textAlign = 'center';
            { text: 'Sundar Pichai', url: '/wiki/Sundar_Pichai', size: 20 },
             ctx.textBaseline = 'middle';
            { text: 'Andy Jassy', url: '/wiki/Andy_Jassy', size: 18 },
            ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
            { text: 'Jensen Huang', url: '/wiki/Jensen_Huang', size: 22 },
             ctx.shadowBlur = 4;
            { text: 'Lisa Su', url: '/wiki/Lisa_Su', size: 18 },
             ctx.shadowOffsetX = 0;
            { text: 'Mary Barra', url: '/wiki/Mary_Barra', size: 18 },
             ctx.shadowOffsetY = 2;
             { text: 'Jamie Dimon', url: '/wiki/Jamie_Dimon', size: 18 },
             ctx.fillText(tag.text, x, y);
             { text: 'Microsoft', url: '/wiki/Microsoft', size: 16 },
             ctx.restore();
             { text: 'Apple', url: '/wiki/Apple_Inc.', size: 16 },
              
             { text: 'Amazon', url: '/wiki/Amazon', size: 16 },
            tag.cx = x;
             { text: 'Google', url: '/wiki/Google', size: 16 },
             tag.cy = y;
             { text: 'Tesla', url: '/wiki/Tesla', size: 16 },
             { text: 'Leadership', url: '/wiki/Category:Chief_executive_officers', size: 14 },
             { text: 'Innovation', url: '/wiki/Category:Business_strategies', size: 14 },
            { text: 'Technology', url: '/wiki/Category:Companies', size: 14 },
             { text: 'Strategy', url: '/wiki/Category:Business_strategies', size: 14 },
             { text: 'Cloud Computing', url: '/wiki/Category:Industry_analysis', size: 14 }
        ];
       
        // Initialize 3D positions
        var radius = 180;
        var dtr = Math.PI / 180;
        var mcList = [];
        var lasta = 1;
        var lastb = 1;
        var tspeed = 0.5;
        var size = 250;
        var mouseX = 0;
        var mouseY = 0;
        var active = false;
       
        // Build tag objects
        for (var i = 0; i < tags.length; i++) {
             var oTag = {};
             oTag.offsetWidth = tags[i].size * 5;
             oTag.offsetHeight = tags[i].size;
             oTag.text = tags[i].text;
             oTag.url = tags[i].url;
             oTag.size = tags[i].size;
             mcList.push(oTag);
         }
         }
    }
   
    function depthSort() {
        mcList.sort(function(a, b) {
            return (b.cz - a.cz);
        });
    }
   
    function update() {
        var a, b;
          
          
         if (active) {
         var sa, ca, sb, cb, sc, cc;
             a = (-Math.min(Math.max(-mouseY, -size), size) / radius) * tspeed;
       
             b = (Math.min(Math.max(-mouseX, -size), size) / radius) * tspeed;
        function sineCosine(a, b, c) {
        } else {
             sa = Math.sin(a * dtr);
             a = lasta * 0.98;
            ca = Math.cos(a * dtr);
             b = lastb * 0.98 + 0.01;
             sb = Math.sin(b * dtr);
            cb = Math.cos(b * dtr);
             sc = Math.sin(c * dtr);
             cc = Math.cos(c * dtr);
         }
         }
          
          
         lasta = a;
         function positionAll() {
        lastb = b;
            var phi = 0;
            var theta = 0;
            var max = mcList.length;
           
            for (var i = 0; i < max; i++) {
                phi = Math.acos(-1 + (2 * i + 1) / max);
                theta = Math.sqrt(max * Math.PI) * phi;
               
                mcList[i].cx = radius * Math.cos(theta) * Math.sin(phi);
                mcList[i].cy = radius * Math.sin(theta) * Math.sin(phi);
                mcList[i].cz = radius * Math.cos(phi);
            }
        }
          
          
         if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01) {
         function doPosition() {
             return;
            ctx.clearRect(0, 0, width, height);
           
            for (var i = 0; i < mcList.length; i++) {
                var tag = mcList[i];
                var x = tag.x + width / 2;
                var y = tag.y + height / 2;
               
                var alpha = Math.max(0.2, Math.min(1, tag.alpha));
                var fontSize = Math.max(10, tag.size * tag.scale);
               
                ctx.save();
                ctx.font = fontSize + 'px sans-serif';
                ctx.fillStyle = 'rgba(255, 255, 255, ' + alpha + ')';
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
                ctx.shadowBlur = 4;
                ctx.shadowOffsetX = 0;
                ctx.shadowOffsetY = 2;
                ctx.fillText(tag.text, x, y);
                ctx.restore();
               
                tag.cx = x;
                tag.cy = y;
             }
         }
         }
          
          
         var c = 0;
         function depthSort() {
        sineCosine(a, b, c);
            mcList.sort(function(a, b) {
                return (b.cz - a.cz);
            });
        }
          
          
         for (var i = 0; i < mcList.length; i++) {
         function update() {
            var rx1 = mcList[i].cx;
            var a, b;
            var ry1 = mcList[i].cy * ca + mcList[i].cz * (-sa);
           
             var rz1 = mcList[i].cy * sa + mcList[i].cz * ca;
            if (active) {
                a = (-Math.min(Math.max(-mouseY, -size), size) / radius) * tspeed;
                b = (Math.min(Math.max(-mouseX, -size), size) / radius) * tspeed;
             } else {
                a = lasta * 0.98;
                b = lastb * 0.98 + 0.01;
            }
              
              
             var rx2 = rx1 * cb + rz1 * sb;
             lasta = a;
             var ry2 = ry1;
             lastb = b;
            var rz2 = rx1 * (-sb) + rz1 * cb;
              
              
             var rx3 = rx2 * cc + ry2 * (-sc);
             if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01) {
            var ry3 = rx2 * sc + ry2 * cc;
                return;
             var rz3 = rz2;
             }
              
              
             mcList[i].cx = rx3;
             var c = 0;
             mcList[i].cy = ry3;
             sineCosine(a, b, c);
            mcList[i].cz = rz3;
              
              
             var per = size / (size + rz3);
             for (var i = 0; i < mcList.length; i++) {
                var rx1 = mcList[i].cx;
                var ry1 = mcList[i].cy * ca + mcList[i].cz * (-sa);
                var rz1 = mcList[i].cy * sa + mcList[i].cz * ca;
               
                var rx2 = rx1 * cb + rz1 * sb;
                var ry2 = ry1;
                var rz2 = rx1 * (-sb) + rz1 * cb;
               
                var rx3 = rx2 * cc + ry2 * (-sc);
                var ry3 = rx2 * sc + ry2 * cc;
                var rz3 = rz2;
               
                mcList[i].cx = rx3;
                mcList[i].cy = ry3;
                mcList[i].cz = rz3;
               
                var per = size / (size + rz3);
               
                mcList[i].x = rx3 * per;
                mcList[i].y = ry3 * per;
                mcList[i].scale = per;
                mcList[i].alpha = per;
                mcList[i].alpha = (mcList[i].alpha - 0.6) * (10 / 6);
            }
              
              
             mcList[i].x = rx3 * per;
             doPosition();
             mcList[i].y = ry3 * per;
             depthSort();
            mcList[i].scale = per;
            mcList[i].alpha = per;
            mcList[i].alpha = (mcList[i].alpha - 0.6) * (10 / 6);
         }
         }
          
          
         doPosition();
         // Event handlers
        depthSort();
        canvas.onmouseover = function() {
    }
            active = true;
   
        };
    // Event handlers
       
    canvas.onmouseover = function() {
        canvas.onmouseout = function() {
        active = true;
            active = false;
    };
        };
   
       
    canvas.onmouseout = function() {
        canvas.onmousemove = function(ev) {
        active = false;
            var rect = canvas.getBoundingClientRect();
    };
            mouseX = ev.clientX - rect.left - width / 2;
   
            mouseY = ev.clientY - rect.top - height / 2;
    canvas.onmousemove = function(ev) {
        };
        var rect = canvas.getBoundingClientRect();
        mouseX = ev.clientX - rect.left - width / 2;
        mouseY = ev.clientY - rect.top - height / 2;
    };
   
    canvas.onclick = function(ev) {
        var rect = canvas.getBoundingClientRect();
        var mx = ev.clientX - rect.left;
        var my = ev.clientY - rect.top;
          
          
         for (var i = 0; i < mcList.length; i++) {
         canvas.onclick = function(ev) {
             var tag = mcList[i];
             var rect = canvas.getBoundingClientRect();
             var dx = mx - tag.cx;
             var mx = ev.clientX - rect.left;
             var dy = my - tag.cy;
             var my = ev.clientY - rect.top;
            var dist = Math.sqrt(dx * dx + dy * dy);
              
              
             if (dist < 50) {
             for (var i = 0; i < mcList.length; i++) {
                window.location.href = tag.url;
                var tag = mcList[i];
                break;
                var dx = mx - tag.cx;
                var dy = my - tag.cy;
                var dist = Math.sqrt(dx * dx + dy * dy);
               
                if (dist < 50) {
                    window.location.href = tag.url;
                    break;
                }
             }
             }
         }
         };
    };
       
   
        canvas.style.cursor = 'pointer';
    canvas.style.cursor = 'pointer';
       
   
        // Initialize
    // Initialize
        sineCosine(0, 0, 0);
    sineCosine(0, 0, 0);
        positionAll();
    positionAll();
        setInterval(update, 30);
    setInterval(update, 30);
       
        console.log('[TagCloud] Successfully initialized! Animation started. You should see tags rotating now!');
    }
      
      
     console.log('[TagCloud] Successfully initialized! Animation started.');
     // Start trying to find the canvas
}
     tryInitialize();
 
})();
// Try multiple initialization methods
if (document.readyState === 'complete') {
     initCEOTagCloud();
} else if (document.readyState === 'interactive') {
    setTimeout(initCEOTagCloud, 100);
} else {
    if (window.addEventListener) {
        window.addEventListener('load', initCEOTagCloud);
        document.addEventListener('DOMContentLoaded', function() {
            setTimeout(initCEOTagCloud, 100);
        });
    } else if (window.attachEvent) {
        window.attachEvent('onload', initCEOTagCloud);
    }
}

Revision as of 10:51, 20 October 2025

/**
 * Add statistics banner to account creation page
 */
(function() {
    // Only run on Special:CreateAccount page
    if (typeof mw !== 'undefined' && mw.config && mw.config.get('wgCanonicalSpecialPageName') !== 'CreateAccount') {
        return;
    }

    if (typeof mw !== 'undefined' && mw.Api && typeof $ !== 'undefined') {
        // Get site statistics via API
        var api = new mw.Api();

        api.get({
            action: 'query',
            meta: 'siteinfo',
            siprop: 'statistics',
            format: 'json'
        }).done(function(data) {
            var stats = data.query.statistics;

            // Create statistics banner
            var banner = $('<div>').addClass('createaccount-statistics').html(
                '<div class="createaccount-statistics-title">CEO.wiki is made by people like you.</div>' +
                '<div class="createaccount-statistics-grid">' +
                    '<div class="createaccount-stat-item">' +
                        '<div class="createaccount-stat-number">' + stats.edits.toLocaleString() + '</div>' +
                        '<div class="createaccount-stat-label">Edits</div>' +
                    '</div>' +
                    '<div class="createaccount-stat-item">' +
                        '<div class="createaccount-stat-number">' + stats.pages.toLocaleString() + '</div>' +
                        '<div class="createaccount-stat-label">Pages</div>' +
                    '</div>' +
                    '<div class="createaccount-stat-item">' +
                        '<div class="createaccount-stat-number">' + stats.activeusers.toLocaleString() + '</div>' +
                        '<div class="createaccount-stat-label">Recent Contributors</div>' +
                    '</div>' +
                '</div>'
            );

            // Insert banner before the form
            $('#userloginForm').before(banner);
        });
    }
})();

/**
 * Simple 3D Rotating Tag Cloud - With Polling for Canvas Element
 */
(function() {
    'use strict';
    
    console.log('[TagCloud] Script loaded');
    
    // Check if we're on Main Page
    if (typeof mw !== 'undefined' && mw.config) {
        var pageName = mw.config.get('wgPageName');
        console.log('[TagCloud] Page name:', pageName);
        if (pageName !== 'Main_Page') {
            console.log('[TagCloud] Not Main Page, exiting');
            return;
        }
    }
    
    var attempts = 0;
    var maxAttempts = 50; // Try for 5 seconds (50 * 100ms)
    
    function tryInitialize() {
        attempts++;
        
        var canvas = document.getElementById('tagcanvas');
        if (!canvas) {
            if (attempts < maxAttempts) {
                console.log('[TagCloud] Canvas not found yet, retrying... (attempt ' + attempts + '/' + maxAttempts + ')');
                setTimeout(tryInitialize, 100);
            } else {
                console.error('[TagCloud] Canvas element not found after ' + maxAttempts + ' attempts. Giving up.');
            }
            return;
        }
        
        console.log('[TagCloud] Canvas found after ' + attempts + ' attempts! Initializing...');
        
        // Hide the fallback list
        var ul = canvas.querySelector('ul');
        if (ul) {
            ul.style.display = 'none';
            console.log('[TagCloud] Fallback list hidden');
        }
        
        var ctx = canvas.getContext('2d');
        if (!ctx) {
            console.error('[TagCloud] Could not get 2D context');
            return;
        }
        
        var width = canvas.width;
        var height = canvas.height;
        
        console.log('[TagCloud] Canvas size:', width, 'x', height);
        
        // Tags configuration
        var tags = [
            { text: 'Satya Nadella', url: '/wiki/Satya_Nadella', size: 24 },
            { text: 'Tim Cook', url: '/wiki/Tim_Cook', size: 22 },
            { text: 'Elon Musk', url: '/wiki/Elon_Musk', size: 26 },
            { text: 'Mark Zuckerberg', url: '/wiki/Mark_Zuckerberg', size: 20 },
            { text: 'Sundar Pichai', url: '/wiki/Sundar_Pichai', size: 20 },
            { text: 'Andy Jassy', url: '/wiki/Andy_Jassy', size: 18 },
            { text: 'Jensen Huang', url: '/wiki/Jensen_Huang', size: 22 },
            { text: 'Lisa Su', url: '/wiki/Lisa_Su', size: 18 },
            { text: 'Mary Barra', url: '/wiki/Mary_Barra', size: 18 },
            { text: 'Jamie Dimon', url: '/wiki/Jamie_Dimon', size: 18 },
            { text: 'Microsoft', url: '/wiki/Microsoft', size: 16 },
            { text: 'Apple', url: '/wiki/Apple_Inc.', size: 16 },
            { text: 'Amazon', url: '/wiki/Amazon', size: 16 },
            { text: 'Google', url: '/wiki/Google', size: 16 },
            { text: 'Tesla', url: '/wiki/Tesla', size: 16 },
            { text: 'Leadership', url: '/wiki/Category:Chief_executive_officers', size: 14 },
            { text: 'Innovation', url: '/wiki/Category:Business_strategies', size: 14 },
            { text: 'Technology', url: '/wiki/Category:Companies', size: 14 },
            { text: 'Strategy', url: '/wiki/Category:Business_strategies', size: 14 },
            { text: 'Cloud Computing', url: '/wiki/Category:Industry_analysis', size: 14 }
        ];
        
        // Initialize 3D positions
        var radius = 180;
        var dtr = Math.PI / 180;
        var mcList = [];
        var lasta = 1;
        var lastb = 1;
        var tspeed = 0.5;
        var size = 250;
        var mouseX = 0;
        var mouseY = 0;
        var active = false;
        
        // Build tag objects
        for (var i = 0; i < tags.length; i++) {
            var oTag = {};
            oTag.offsetWidth = tags[i].size * 5;
            oTag.offsetHeight = tags[i].size;
            oTag.text = tags[i].text;
            oTag.url = tags[i].url;
            oTag.size = tags[i].size;
            mcList.push(oTag);
        }
        
        var sa, ca, sb, cb, sc, cc;
        
        function sineCosine(a, b, c) {
            sa = Math.sin(a * dtr);
            ca = Math.cos(a * dtr);
            sb = Math.sin(b * dtr);
            cb = Math.cos(b * dtr);
            sc = Math.sin(c * dtr);
            cc = Math.cos(c * dtr);
        }
        
        function positionAll() {
            var phi = 0;
            var theta = 0;
            var max = mcList.length;
            
            for (var i = 0; i < max; i++) {
                phi = Math.acos(-1 + (2 * i + 1) / max);
                theta = Math.sqrt(max * Math.PI) * phi;
                
                mcList[i].cx = radius * Math.cos(theta) * Math.sin(phi);
                mcList[i].cy = radius * Math.sin(theta) * Math.sin(phi);
                mcList[i].cz = radius * Math.cos(phi);
            }
        }
        
        function doPosition() {
            ctx.clearRect(0, 0, width, height);
            
            for (var i = 0; i < mcList.length; i++) {
                var tag = mcList[i];
                var x = tag.x + width / 2;
                var y = tag.y + height / 2;
                
                var alpha = Math.max(0.2, Math.min(1, tag.alpha));
                var fontSize = Math.max(10, tag.size * tag.scale);
                
                ctx.save();
                ctx.font = fontSize + 'px sans-serif';
                ctx.fillStyle = 'rgba(255, 255, 255, ' + alpha + ')';
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
                ctx.shadowBlur = 4;
                ctx.shadowOffsetX = 0;
                ctx.shadowOffsetY = 2;
                ctx.fillText(tag.text, x, y);
                ctx.restore();
                
                tag.cx = x;
                tag.cy = y;
            }
        }
        
        function depthSort() {
            mcList.sort(function(a, b) {
                return (b.cz - a.cz);
            });
        }
        
        function update() {
            var a, b;
            
            if (active) {
                a = (-Math.min(Math.max(-mouseY, -size), size) / radius) * tspeed;
                b = (Math.min(Math.max(-mouseX, -size), size) / radius) * tspeed;
            } else {
                a = lasta * 0.98;
                b = lastb * 0.98 + 0.01;
            }
            
            lasta = a;
            lastb = b;
            
            if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01) {
                return;
            }
            
            var c = 0;
            sineCosine(a, b, c);
            
            for (var i = 0; i < mcList.length; i++) {
                var rx1 = mcList[i].cx;
                var ry1 = mcList[i].cy * ca + mcList[i].cz * (-sa);
                var rz1 = mcList[i].cy * sa + mcList[i].cz * ca;
                
                var rx2 = rx1 * cb + rz1 * sb;
                var ry2 = ry1;
                var rz2 = rx1 * (-sb) + rz1 * cb;
                
                var rx3 = rx2 * cc + ry2 * (-sc);
                var ry3 = rx2 * sc + ry2 * cc;
                var rz3 = rz2;
                
                mcList[i].cx = rx3;
                mcList[i].cy = ry3;
                mcList[i].cz = rz3;
                
                var per = size / (size + rz3);
                
                mcList[i].x = rx3 * per;
                mcList[i].y = ry3 * per;
                mcList[i].scale = per;
                mcList[i].alpha = per;
                mcList[i].alpha = (mcList[i].alpha - 0.6) * (10 / 6);
            }
            
            doPosition();
            depthSort();
        }
        
        // Event handlers
        canvas.onmouseover = function() {
            active = true;
        };
        
        canvas.onmouseout = function() {
            active = false;
        };
        
        canvas.onmousemove = function(ev) {
            var rect = canvas.getBoundingClientRect();
            mouseX = ev.clientX - rect.left - width / 2;
            mouseY = ev.clientY - rect.top - height / 2;
        };
        
        canvas.onclick = function(ev) {
            var rect = canvas.getBoundingClientRect();
            var mx = ev.clientX - rect.left;
            var my = ev.clientY - rect.top;
            
            for (var i = 0; i < mcList.length; i++) {
                var tag = mcList[i];
                var dx = mx - tag.cx;
                var dy = my - tag.cy;
                var dist = Math.sqrt(dx * dx + dy * dy);
                
                if (dist < 50) {
                    window.location.href = tag.url;
                    break;
                }
            }
        };
        
        canvas.style.cursor = 'pointer';
        
        // Initialize
        sineCosine(0, 0, 0);
        positionAll();
        setInterval(update, 30);
        
        console.log('[TagCloud] Successfully initialized! Animation started. You should see tags rotating now!');
    }
    
    // Start trying to find the canvas
    tryInitialize();
})();