T.ME/BIBIL_0DAY
CasperSecurity


Server : Apache/2
System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User : gositeme ( 1004)
PHP Version : 8.2.29
Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Directory :  /home/gositeme/.cursor-server/data/User/History/6b963d87/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/.cursor-server/data/User/History/6b963d87/i7fM.js
/**
 * Homepage Map - SIMPLE WORKING VERSION
 * Uses exact same coordinate system as advanced map
 */

(function() {
    'use strict';

    const BOUNDS = {
        minLat: 45.0,
        maxLat: 51.0,
        minLng: -80.0,
        maxLng: -66.0
    };

    let map = {
        canvas: null,
        ctx: null,
        container: null,
        cities: [],
        villages: [],
        zoom: 1.2,
        panX: 0,
        panY: 0,
        dragging: false,
        dragStart: { x: 0, y: 0 }
    };

    function init() {
        console.log('🗺️ INIT: Starting homepage map');
        
        map.container = document.getElementById('homepageInteractiveMap');
        map.canvas = document.getElementById('homepageMapCanvas');
        
        if (!map.container || !map.canvas) {
            console.error('🗺️ ERROR: Container or canvas missing');
            return;
        }

        map.ctx = map.canvas.getContext('2d');
        if (!map.ctx) {
            console.error('🗺️ ERROR: No canvas context');
            return;
        }

        setupCanvas();
        setupControls();
        loadData();
    }

    function setupCanvas() {
        const rect = map.container.getBoundingClientRect();
        if (rect.width === 0 || rect.height === 0) {
            setTimeout(setupCanvas, 100);
            return;
        }
        
        map.canvas.width = rect.width;
        map.canvas.height = rect.height;
        map.panX = map.canvas.width / 2;
        map.panY = map.canvas.height / 2;
        
        console.log('🗺️ Canvas:', map.canvas.width, 'x', map.canvas.height);

        map.canvas.addEventListener('mousedown', (e) => {
            map.dragging = true;
            const rect = map.canvas.getBoundingClientRect();
            map.dragStart.x = e.clientX - rect.left;
            map.dragStart.y = e.clientY - rect.top;
        });

        map.canvas.addEventListener('mousemove', (e) => {
            if (map.dragging) {
                const rect = map.canvas.getBoundingClientRect();
                const x = e.clientX - rect.left;
                const y = e.clientY - rect.top;
                map.panX += x - map.dragStart.x;
                map.panY += y - map.dragStart.y;
                map.dragStart.x = x;
                map.dragStart.y = y;
                draw();
            }
        });

        map.canvas.addEventListener('mouseup', () => {
            map.dragging = false;
        });

        map.canvas.addEventListener('wheel', (e) => {
            e.preventDefault();
            const rect = map.canvas.getBoundingClientRect();
            const x = e.clientX - rect.left;
            const y = e.clientY - rect.top;
            const oldZoom = map.zoom;
            map.zoom *= e.deltaY > 0 ? 0.9 : 1.1;
            map.zoom = Math.max(0.5, Math.min(5, map.zoom));
            const zoomChange = map.zoom / oldZoom;
            map.panX = x - (x - map.panX) * zoomChange;
            map.panY = y - (y - map.panY) * zoomChange;
            draw();
        });

        window.addEventListener('resize', () => {
            const rect = map.container.getBoundingClientRect();
            if (rect.width > 0 && rect.height > 0) {
                map.canvas.width = rect.width;
                map.canvas.height = rect.height;
                draw();
            }
        });
    }

    function setupControls() {
        const zoomIn = document.getElementById('mapZoomIn');
        const zoomOut = document.getElementById('mapZoomOut');
        const reset = document.getElementById('resetMapView');

        if (zoomIn) zoomIn.onclick = () => { map.zoom = Math.min(5, map.zoom * 1.2); draw(); };
        if (zoomOut) zoomOut.onclick = () => { map.zoom = Math.max(0.5, map.zoom / 1.2); draw(); };
        if (reset) reset.onclick = () => {
            map.zoom = 1.2;
            map.panX = map.canvas.width / 2;
            map.panY = map.canvas.height / 2;
            draw();
        };
    }

    function latLngToXY(lat, lng) {
        // EXACT same formula as advanced map
        const x = ((lng - BOUNDS.minLng) / (BOUNDS.maxLng - BOUNDS.minLng)) * map.canvas.width * map.zoom + (map.panX - (map.canvas.width * map.zoom) / 2);
        const y = ((BOUNDS.maxLat - lat) / (BOUNDS.maxLat - BOUNDS.minLat)) * map.canvas.height * map.zoom + (map.panY - (map.canvas.height * map.zoom) / 2);
        return { x, y };
    }

    function loadData() {
        // Wait for quebecMunicipalities
        let attempts = 0;
        function tryLoad() {
            attempts++;
            if (window.quebecMunicipalities && Object.keys(window.quebecMunicipalities).length > 0) {
                console.log('🗺️ Found quebecMunicipalities:', Object.keys(window.quebecMunicipalities).length, 'cities');
                loadCities();
                loadVillages();
            } else if (attempts < 100) {
                setTimeout(tryLoad, 100);
            } else {
                console.error('🗺️ ERROR: quebecMunicipalities not found after 10 seconds');
                // Try loading anyway
                loadCities();
                loadVillages();
            }
        }
        tryLoad();
    }

    function loadCities() {
        if (!window.quebecMunicipalities) {
            console.error('🗺️ ERROR: quebecMunicipalities not available');
            return;
        }

        map.cities = [];
        for (const [name, data] of Object.entries(window.quebecMunicipalities)) {
            if (!data || !data.lat || !data.lng) continue;
            const lat = parseFloat(data.lat);
            const lng = parseFloat(data.lng);
            if (isNaN(lat) || isNaN(lng)) continue;
            if (lat >= BOUNDS.minLat && lat <= BOUNDS.maxLat &&
                lng >= BOUNDS.minLng && lng <= BOUNDS.maxLng) {
                map.cities.push({
                    name: name,
                    lat: lat,
                    lng: lng,
                    population: parseInt(data.population) || 0,
                    region: data.region || '',
                    member_count: 0
                });
            }
        }
        
        console.log('🗺️ Loaded', map.cities.length, 'cities');
        if (map.cities.length > 0) {
            console.log('🗺️ First 3 cities:', map.cities.slice(0, 3).map(c => c.name));
        }
        draw();
    }

    function loadVillages() {
        fetch('/api/map')
            .then(res => res.json())
            .then(data => {
                const villages = data.villages || data.cities || [];
                map.villages = villages
                    .map(v => {
                        const lat = parseFloat(v.location_lat || v.lat);
                        const lng = parseFloat(v.location_lng || v.lng);
                        if (isNaN(lat) || isNaN(lng)) return null;
                        return {
                            id: v.id,
                            name: v.name,
                            name_fr: v.name_fr,
                            slug: v.slug,
                            lat: lat,
                            lng: lng,
                            status: v.status || 'forming',
                            member_count: v.member_count || 0
                        };
                    })
                    .filter(v => v !== null && 
                        v.lat >= BOUNDS.minLat && v.lat <= BOUNDS.maxLat &&
                        v.lng >= BOUNDS.minLng && v.lng <= BOUNDS.maxLng
                    );
                
                console.log('🗺️ Loaded', map.villages.length, 'villages');
                
                // Merge into cities
                villages.forEach(v => {
                    if (!v.location_lat || !v.location_lng) return;
                    const vLat = parseFloat(v.location_lat);
                    const vLng = parseFloat(v.location_lng);
                    if (isNaN(vLat) || isNaN(vLng)) return;
                    
                    let closest = null;
                    let minDist = Infinity;
                    map.cities.forEach(city => {
                        const dist = Math.sqrt(Math.pow(city.lat - vLat, 2) + Math.pow(city.lng - vLng, 2));
                        if (dist < minDist && dist < 0.1) {
                            minDist = dist;
                            closest = city;
                        }
                    });
                    if (closest) {
                        closest.member_count += v.member_count || 0;
                    }
                });
                
                draw();
            })
            .catch(err => console.error('🗺️ ERROR loading villages:', err));
    }

    function draw() {
        if (!map.ctx || !map.canvas || map.canvas.width === 0 || map.canvas.height === 0) {
            return;
        }

        const ctx = map.ctx;
        const w = map.canvas.width;
        const h = map.canvas.height;

        // Clear
        ctx.clearRect(0, 0, w, h);

        // Background
        ctx.fillStyle = getComputedStyle(document.documentElement).getPropertyValue('--color-bg-light').trim() || '#1a1a1a';
        ctx.fillRect(0, 0, w, h);

        // Grid
        ctx.strokeStyle = 'rgba(212, 165, 116, 0.1)';
        ctx.lineWidth = 1;
        for (let x = 0; x < w; x += 50) {
            ctx.beginPath();
            ctx.moveTo(x, 0);
            ctx.lineTo(x, h);
            ctx.stroke();
        }
        for (let y = 0; y < h; y += 50) {
            ctx.beginPath();
            ctx.moveTo(0, y);
            ctx.lineTo(w, y);
            ctx.stroke();
        }

        // Draw cities
        if (map.cities.length === 0) {
            ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
            ctx.font = '16px sans-serif';
            ctx.textAlign = 'center';
            ctx.fillText('Loading cities...', w / 2, h / 2);
            console.log('🗺️ DRAW: No cities to draw');
            return;
        }

        console.log('🗺️ DRAW: Drawing', map.cities.length, 'cities');
        
        map.cities.forEach(city => {
            const pos = latLngToXY(city.lat, city.lng);
            
            if (isNaN(pos.x) || isNaN(pos.y)) {
                console.log('🗺️ Invalid pos for', city.name, pos);
                return;
            }
            
            // Only draw if on screen
            if (pos.x < -50 || pos.x > w + 50 || pos.y < -50 || pos.y > h + 50) return;

            const isMajor = city.population > 100000;
            const isMedium = city.population > 50000;
            const hasMembers = (city.member_count || 0) > 0;
            
            const radius = isMajor ? 12 : isMedium ? 8 : city.population > 10000 ? 5 : 3;
            const color = hasMembers ? '#d4a574' : (isMajor ? '#d4a574' : isMedium ? '#8bc34a' : '#6496c8');
            const opacity = hasMembers ? 0.9 : 0.7;

            // Glow for cities with members
            if (hasMembers) {
                const gradient = ctx.createRadialGradient(pos.x, pos.y, 0, pos.x, pos.y, radius * 3);
                gradient.addColorStop(0, 'rgba(212, 165, 116, 0.5)');
                gradient.addColorStop(1, 'rgba(212, 165, 116, 0)');
                ctx.fillStyle = gradient;
                ctx.beginPath();
                ctx.arc(pos.x, pos.y, radius * 3, 0, Math.PI * 2);
                ctx.fill();
            }

            // City circle
            ctx.fillStyle = color;
            ctx.globalAlpha = opacity;
            ctx.beginPath();
            ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);
            ctx.fill();

            ctx.strokeStyle = color;
            ctx.globalAlpha = 1;
            ctx.lineWidth = hasMembers ? 3 : 2;
            ctx.stroke();

            // Member dot
            if (hasMembers) {
                ctx.fillStyle = '#10b981';
                ctx.beginPath();
                ctx.arc(pos.x + radius * 0.6, pos.y - radius * 0.6, radius * 0.3, 0, Math.PI * 2);
                ctx.fill();
            }

            // Label
            if ((isMajor || hasMembers || map.zoom > 1.8) && map.zoom > 1.2) {
                const labelText = city.name + (hasMembers ? ` (${city.member_count})` : '');
                ctx.fillStyle = 'rgba(0, 0, 0, 0.8)';
                ctx.font = '12px sans-serif';
                const metrics = ctx.measureText(labelText);
                const pad = 6;
                ctx.fillRect(pos.x - metrics.width / 2 - pad, pos.y + radius + 2, metrics.width + pad * 2, 18);
                
                ctx.fillStyle = color;
                ctx.textAlign = 'center';
                ctx.textBaseline = 'top';
                ctx.fillText(labelText, pos.x, pos.y + radius + 5);
            }
        });

        // Draw villages
        map.villages.forEach(village => {
            const pos = latLngToXY(village.lat, village.lng);
            if (pos.x < -50 || pos.x > w + 50 || pos.y < -50 || pos.y > h + 50) return;

            const hasMembers = (village.member_count || 0) > 0;
            const radius = Math.max(8, Math.min(20, 8 + (village.member_count || 0) * 0.5));
            const color = '#d4a574';

            // Glow
            if (hasMembers) {
                const gradient = ctx.createRadialGradient(pos.x, pos.y, 0, pos.x, pos.y, radius * 4);
                gradient.addColorStop(0, 'rgba(212, 165, 116, 0.8)');
                gradient.addColorStop(1, 'rgba(212, 165, 116, 0)');
                ctx.fillStyle = gradient;
                ctx.beginPath();
                ctx.arc(pos.x, pos.y, radius * 4, 0, Math.PI * 2);
                ctx.fill();
            }

            // Outer ring
            ctx.strokeStyle = 'rgba(212, 165, 116, 1)';
            ctx.lineWidth = 3;
            ctx.beginPath();
            ctx.arc(pos.x, pos.y, radius + 2, 0, Math.PI * 2);
            ctx.stroke();

            // Village circle
            ctx.fillStyle = color;
            ctx.globalAlpha = hasMembers ? 0.9 : 0.7;
            ctx.beginPath();
            ctx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);
            ctx.fill();

            ctx.strokeStyle = color;
            ctx.globalAlpha = 1;
            ctx.lineWidth = 2;
            ctx.stroke();

            // Label
            if (map.zoom > 1.5 || hasMembers) {
                const name = (document.documentElement.lang === 'fr' && village.name_fr) ? village.name_fr : village.name;
                const labelText = name + (hasMembers ? ` (${village.member_count})` : '');
                
                ctx.fillStyle = 'rgba(0, 0, 0, 0.9)';
                ctx.font = '13px sans-serif';
                const metrics = ctx.measureText(labelText);
                const pad = 8;
                ctx.fillRect(pos.x - metrics.width / 2 - pad, pos.y + radius + 3, metrics.width + pad * 2, 20);
                
                ctx.fillStyle = color;
                ctx.textAlign = 'center';
                ctx.textBaseline = 'top';
                ctx.fillText(labelText, pos.x, pos.y + radius + 5);
            }
        });
    }

    // Initialize
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        setTimeout(init, 100);
    }
})();

CasperSecurity Mini