Mudanças entre as edições de "Widget:MapViewer.js"

De Wiki Gla
Ir para navegação Ir para pesquisar
 
(2 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 1: Linha 1:
<includeonly><div id="mapa-debug-<!--{$id|escape:'quotes'|default:'teste'}-->" style="width:<!--{$largura|escape:'quotes'|default:'100%'}-->; min-height:<!--{$altura|escape:'quotes'|default:'500px'}-->; background:#0f172a; border-radius:12px; padding:20px; font-family:monospace; color:#e2e8f0;">
<includeonly><div id="mapa-viewer-<!--{$id|escape:'quotes'|default:'mapa1'}-->" style="width:<!--{$largura|escape:'quotes'|default:'100%'}-->; height:<!--{$altura|escape:'quotes'|default:'500px'}-->; background:#0f172a; border-radius:12px; overflow:hidden; position:relative;">
    <div style="background:#1e293b; padding:15px; border-radius:8px; margin-bottom:10px;">
    <div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); color:#64748b; text-align:center;">
        <strong>🐛 DEBUG MODE - Visualizador de Mapas</strong>
        🗺️ Carregando mapa...
        <div id="debug-log-<!--{$id|escape:'quotes'}-->" style="margin-top:10px; font-size:12px;"></div>
    </div>
    <div id="mapa-container-<!--{$id|escape:'quotes'}-->" style="min-height:400px; background:#0f172a; border:1px solid #334155; border-radius:8px; position:relative;">
        <div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); text-align:center;">
            ⏳ Aguardando carregamento...<br>
            <small style="color:#64748b;">Verifique o console do navegador (F12)</small>
        </div>
     </div>
     </div>
</div>
</div>
Linha 15: Linha 8:
// @noescape
// @noescape
(function() {
(function() {
     var id = '<!--{$id|escape:'quotes'|default:'teste'}-->';
     var id = '<!--{$id|escape:'quotes'|default:'mapa1'}-->';
     var debugDiv = document.getElementById('debug-log-' + id);
     var container = document.getElementById('mapa-viewer-' + id);
     var container = document.getElementById('mapa-container-' + id);
     if (!container) return;
    var jsonRaw = '<!--{$json|escape:'quotes'}-->';
// PEGAR O JSON DIRETAMENTE COMO TEXTO BRUTO
    var jsonBruto = `<!--{$json}-->`;
      
      
     // LIMPAR O JSON: remover espaços extras e quebras
     // JSON vem URL encoded para não quebrar o parser
     jsonRaw= jsonBruto.replace(/\s+/g, ' ');
     var jsonEncoded = '<!--{$json|escape:'quotes'}-->';
     jsonRaw= jsonBruto.trim();
     var jsonString = decodeURIComponent(jsonEncoded);
      
      
    console.log('JSON bruto:', jsonRaw.substring(0, 200));
     var mapConfig;
   
     var config;
     try {
     try {
         config = JSON.parse(jsonBruto);
         mapConfig = JSON.parse(jsonString);
        console.log('✅ JSON válido!', config.layers.length, 'camadas');
     } catch(e) {
     } catch(e) {
        console.error('❌ Erro JSON:', e.message);
         container.innerHTML = '<div style="padding:20px; text-align:center; color:#ef4444;">❌ Erro no JSON: ' + e.message + '</div>';
         container.innerHTML = '<div style="padding:20px; text-align:center; color:#ef4444;">❌ Erro no JSON: ' + e.message + '</div>';
         return;
         return;
    }
   
    function log(msg, type) {
        var color = '#10b981';
        if (type === 'error') color = '#ef4444';
        if (type === 'warning') color = '#f59e0b';
        if (type === 'info') color = '#3b82f6';
        var timestamp = new Date().toLocaleTimeString();
        debugDiv.innerHTML += '<div style="color:' + color + '; border-bottom:1px solid #334155; padding:4px 0;">[' + timestamp + '] ' + msg + '</div>';
        console.log('[MapaDebug]', msg);
     }
     }
      
      
     log('🔧 Iniciando debug do mapa...', 'info');
     if (!mapConfig.layers || mapConfig.layers.length === 0) {
    log('📌 ID do container: ' + id, 'info');
         container.innerHTML = '<div style="padding:20px; text-align:center; color:#f59e0b;">⚠️ Nenhuma camada configurada</div>';
    log('📏 Largura: <!--{$largura|escape:'quotes'|default:'100%'}-->', 'info');
    log('📐 Altura: <!--{$altura|escape:'quotes'|default:'500px'}-->', 'info');
    log('📝 Título: <!--{$titulo|escape:'quotes'|default:'Mapa'}-->', 'info');
    log('📦 JSON raw length: ' + jsonRaw.length, 'info');
    log('📦 JSON raw preview: ' + jsonRaw.substring(0, 200) + (jsonRaw.length > 200 ? '...' : ''), 'info');
   
    if (!jsonRaw || jsonRaw === '') {
        log('❌ NENHUM JSON FORNECIDO! Use o parâmetro |json=...', 'error');
         container.innerHTML = '<div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); text-align:center; color:#ef4444;">❌ Nenhum JSON fornecido<br><small>Use o parâmetro |json=...</small></div>';
         return;
         return;
     }
     }
      
      
     log('✅ JSON recebido, tentando parse...', 'info');
     // Iniciar o visualizador
    iniciarMapaViewer(container, mapConfig);
      
      
     var mapConfig = null;
     function iniciarMapaViewer(container, config) {
    try {
        container.innerHTML = '';
         mapConfig = JSON.parse(jsonRaw);
        container.style.position = 'relative';
         log('✅ JSON parseado com sucesso!', 'success');
        container.style.overflow = 'hidden';
         log('📊 Camadas encontradas: ' + (mapConfig.layers ? mapConfig.layers.length : 0), 'info');
       
        // Toolbar
         var toolbar = document.createElement('div');
         toolbar.style.cssText = 'position:absolute; top:10px; left:10px; right:10px; z-index:100; display:flex; justify-content:space-between; gap:8px; flex-wrap:wrap;';
        toolbar.innerHTML = '<div style="display:flex; gap:5px; background:rgba(0,0,0,0.7); padding:5px 10px; border-radius:30px;">' +
            '<button id="zoom-in-' + id + '" style="background:#334155; border:none; color:white; width:32px; height:32px; border-radius:50%; cursor:pointer;">+</button>' +
            '<button id="zoom-out-' + id + '" style="background:#334155; border:none; color:white; width:32px; height:32px; border-radius:50%; cursor:pointer;">-</button>' +
            '<button id="reset-' + id + '" style="background:#334155; border:none; color:white; width:32px; height:32px; border-radius:50%; cursor:pointer;">⟳</button>' +
            '</div>' +
            '<div style="background:rgba(0,0,0,0.7); padding:5px 15px; border-radius:30px; color:white; font-size:12px;"><span id="floor-name-' + id + '">' + (config.layers[0]?.name || 'Mapa') + '</span></div>' +
            '<div id="zoom-level-' + id + '" style="background:rgba(0,0,0,0.7); padding:5px 12px; border-radius:30px; color:#a5b4fc; font-size:12px;">100%</div>';
       
        // Viewport
        var viewport = document.createElement('div');
         viewport.style.cssText = 'width:100%; height:100%; overflow:auto; cursor:grab; background:#0f172a;';
        var camadasDiv = document.createElement('div');
        camadasDiv.style.cssText = 'position:relative; min-width:100%; min-height:100%;';
        viewport.appendChild(camadasDiv);
       
        // Navegação
        var navDiv = document.createElement('div');
        navDiv.style.cssText = 'position:absolute; bottom:20px; left:20px; z-index:100; display:flex; gap:8px; background:rgba(0,0,0,0.7); padding:8px; border-radius:40px;';
        navDiv.innerHTML = '<button id="prev-' + id + '" style="background:#334155; border:none; color:white; width:36px; height:36px; border-radius:50%; cursor:pointer;">▲</button>' +
            '<button id="next-' + id + '" style="background:#334155; border:none; color:white; width:36px; height:36px; border-radius:50%; cursor:pointer;">▼</button>';
       
        // Coordenadas
        var coordsDiv = document.createElement('div');
        coordsDiv.style.cssText = 'position:absolute; bottom:10px; right:10px; background:rgba(0,0,0,0.6); padding:4px 10px; border-radius:20px; color:#a5b4fc; font-size:10px; font-family:monospace;';
        coordsDiv.textContent = '📍 0, 0';
          
          
         if (mapConfig.layers && mapConfig.layers.length > 0) {
         container.appendChild(toolbar);
            log('📋 Detalhes da primeira camada:', 'info');
        container.appendChild(viewport);
            log('  - Nome: ' + (mapConfig.layers[0].name || 'sem nome'), 'info');
        container.appendChild(coordsDiv);
            log('  - Imagem: ' + (mapConfig.layers[0].imagePath || 'sem imagem'), 'info');
         container.appendChild(navDiv);
            log('  - Marcadores: ' + (mapConfig.layers[0].markers ? mapConfig.layers[0].markers.length : 0), 'info');
         } else {
            log('⚠️ Nenhuma camada encontrada no JSON', 'warning');
        }
          
          
         log('🚀 Iniciando visualizador do mapa...', 'info');
         // Variáveis
         iniciarVisualizador(container, mapConfig, id, log);
        var zoomAtual = config.mapConfig.defaultZoom || 1;
        var andarAtual = config.mapConfig.initialFloor || 0;
        var zoomMin = config.mapConfig.minZoom || 0.5;
        var zoomMax = config.mapConfig.maxZoom || 3;
        var zoomPasso = config.mapConfig.zoomStep || 0.1;
        var camadas = [];
        var marcadores = [];
        var arrastando = false;
         var arrasteInicio = { x: 0, y: 0, scrollLeft: 0, scrollTop: 0 };
          
          
    } catch(e) {
         function renderizarCamadas() {
        log('❌ ERRO AO PARSEAR JSON: ' + e.message, 'error');
             camadasDiv.innerHTML = '';
         log('🔍 Verifique se o JSON está válido. Use um validador JSON online.', 'error');
             camadas = [];
        container.innerHTML = '<div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); text-align:center; color:#ef4444;">❌ Erro no JSON<br><small>' + e.message + '</small></div>';
             marcadores = [];
    }
   
    function iniciarVisualizador(container, config, id, log) {
        try {
             log('📐 Configurações do mapa:', 'info');
            log('  - Zoom inicial: ' + (config.mapConfig?.defaultZoom || 1), 'info');
             log('  - Andar inicial: ' + (config.mapConfig?.initialFloor || 0), 'info');
             log('  - Zoom min: ' + (config.mapConfig?.minZoom || 0.5), 'info');
            log('  - Zoom max: ' + (config.mapConfig?.maxZoom || 3), 'info');
              
              
             // Limpar container
             if (!config.layers || config.layers.length === 0) return;
            container.innerHTML = '';
            container.style.position = 'relative';
            container.style.overflow = 'hidden';
              
              
            // Criar toolbar
             var andarExiste = false;
             var toolbar = document.createElement('div');
             for (var i = 0; i < config.layers.length; i++) {
             toolbar.style.cssText = 'position:absolute; top:10px; left:10px; right:10px; z-index:100; display:flex; justify-content:space-between; gap:8px; flex-wrap:wrap;';
                 if (config.layers[i].id === andarAtual) andarExiste = true;
            toolbar.innerHTML = '<div style="display:flex; gap:5px; background:rgba(0,0,0,0.7); padding:5px 10px; border-radius:30px;">' +
            }
                '<button id="zoom-in-' + id + '" style="background:#334155; border:none; color:white; width:32px; height:32px; border-radius:50%; cursor:pointer;">+</button>' +
            if (!andarExiste && config.layers.length > 0) andarAtual = config.layers[0].id;
                 '<button id="zoom-out-' + id + '" style="background:#334155; border:none; color:white; width:32px; height:32px; border-radius:50%; cursor:pointer;">-</button>' +
                '<button id="reset-' + id + '" style="background:#334155; border:none; color:white; width:32px; height:32px; border-radius:50%; cursor:pointer;">⟳</button>' +
                '</div>' +
                '<div style="background:rgba(0,0,0,0.7); padding:5px 15px; border-radius:30px; color:white; font-size:12px;"><span id="floor-name-' + id + '">' + (config.layers[0]?.name || 'Mapa') + '</span></div>' +
                '<div id="zoom-level-' + id + '" style="background:rgba(0,0,0,0.7); padding:5px 12px; border-radius:30px; color:#a5b4fc; font-size:12px;">100%</div>';
              
              
             var viewport = document.createElement('div');
             var andarInfo = null;
            viewport.style.cssText = 'width:100%; height:100%; overflow:auto; cursor:grab; background:#0f172a;';
             for (var i = 0; i < config.layers.length; i++) {
             var camadasDiv = document.createElement('div');
                if (config.layers[i].id === andarAtual) andarInfo = config.layers[i];
            camadasDiv.style.cssText = 'position:relative; min-width:100%; min-height:100%;';
             }
            viewport.appendChild(camadasDiv);
             var nomeSpan = document.getElementById('floor-name-' + id);
           
             if (nomeSpan && andarInfo) nomeSpan.textContent = andarInfo.name;
            var navDiv = document.createElement('div');
            navDiv.style.cssText = 'position:absolute; bottom:20px; left:20px; z-index:100; display:flex; gap:8px; background:rgba(0,0,0,0.7); padding:8px; border-radius:40px;';
            navDiv.innerHTML = '<button id="prev-' + id + '" style="background:#334155; border:none; color:white; width:36px; height:36px; border-radius:50%; cursor:pointer;">▲</button>' +
                '<button id="next-' + id + '" style="background:#334155; border:none; color:white; width:36px; height:36px; border-radius:50%; cursor:pointer;">▼</button>';
              
             var coordsDiv = document.createElement('div');
            coordsDiv.style.cssText = 'position:absolute; bottom:10px; right:10px; background:rgba(0,0,0,0.6); padding:4px 10px; border-radius:20px; color:#a5b4fc; font-size:10px; font-family:monospace;';
            coordsDiv.textContent = '📍 0, 0';
           
            container.appendChild(toolbar);
             container.appendChild(viewport);
            container.appendChild(coordsDiv);
            container.appendChild(navDiv);
           
            log('✅ Interface criada com sucesso', 'success');
           
            // Variáveis de estado
            var zoomAtual = config.mapConfig?.defaultZoom || 1;
            var andarAtual = config.mapConfig?.initialFloor || 0;
            var zoomMin = config.mapConfig?.minZoom || 0.5;
            var zoomMax = config.mapConfig?.maxZoom || 3;
            var zoomPasso = config.mapConfig?.zoomStep || 0.1;
            var camadas = [];
            var marcadores = [];
            var arrastando = false;
            var arrasteInicio = { x: 0, y: 0, scrollLeft: 0, scrollTop: 0 };
              
              
             log('🎮 Controles inicializados', 'info');
             for (var i = 0; i < config.layers.length; i++) {
           
                 var layer = config.layers[i];
            function renderizarCamadas() {
                var divLayer = document.createElement('div');
                 camadasDiv.innerHTML = '';
                 divLayer.className = 'mapa-layer';
                 camadas = [];
                 divLayer.setAttribute('data-floor', layer.id);
                 marcadores = [];
                 divLayer.style.display = layer.id === andarAtual ? 'block' : 'none';
                  
                divLayer.style.position = 'absolute';
                if (!config.layers || config.layers.length === 0) {
                 divLayer.style.top = '0';
                    log('⚠️ Nenhuma camada para renderizar', 'warning');
                 divLayer.style.left = '0';
                    return;
                divLayer.style.transform = 'translate(' + (layer.alignment?.offsetX || 0) + 'px, ' + (layer.alignment?.offsetY || 0) + 'px)';
                 }
                divLayer.style.opacity = (layer.opacity || 100) / 100;
               
                // Verificar andar atual
                var andarExiste = false;
                 for (var i = 0; i < config.layers.length; i++) {
                    if (config.layers[i].id === andarAtual) andarExiste = true;
                }
                if (!andarExiste && config.layers.length > 0) {
                    andarAtual = config.layers[0].id;
                    log('🔄 Andar ajustado para: ' + andarAtual, 'info');
                }
                  
                  
                 var andarInfo = null;
                 var img = document.createElement('img');
                 for (var i = 0; i < config.layers.length; i++) {
                 img.style.display = 'block';
                    if (config.layers[i].id === andarAtual) andarInfo = config.layers[i];
                img.style.transform = 'scale(' + zoomAtual + ')';
                }
                img.style.transformOrigin = '0 0';
                 var nomeSpan = document.getElementById('floor-name-' + id);
                img.src = layer.imagePath || '';
                 if (nomeSpan && andarInfo) nomeSpan.textContent = andarInfo.name;
                img.onload = function() { camadasDiv.style.width = this.width + 'px'; camadasDiv.style.height = this.height + 'px'; };
                 img.onerror = function() { this.src = 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22800%22 height=%22600%22%3E%3Crect width=%22100%25%22 height=%22100%25%22 fill=%22%23334155%22/%3E%3Ctext x=%2250%25%22 y=%2250%25%22 text-anchor=%22middle%22 fill=%22white%22%3ESem imagem%3C/text%3E%3C/svg%3E'; };
                 divLayer.appendChild(img);
                  
                  
                 log('🎨 Renderizando ' + config.layers.length + ' camada(s)', 'info');
                 var markersDiv = document.createElement('div');
                markersDiv.style.position = 'absolute';
                markersDiv.style.top = '0';
                markersDiv.style.left = '0';
                markersDiv.style.width = '100%';
                markersDiv.style.height = '100%';
                markersDiv.style.pointerEvents = 'none';
                  
                  
                 for (var i = 0; i < config.layers.length; i++) {
                 if (layer.markers) {
                    var layer = config.layers[i];
                    for (var j = 0; j < layer.markers.length; j++) {
                    var divLayer = document.createElement('div');
                        var marker = layer.markers[j];
                    divLayer.className = 'mapa-layer';
                        var markerDiv = criarMarcador(marker, layer.id);
                    divLayer.setAttribute('data-floor', layer.id);
                        markersDiv.appendChild(markerDiv);
                    divLayer.style.display = layer.id === andarAtual ? 'block' : 'none';
                        marcadores.push({ el: markerDiv, data: marker });
                    divLayer.style.position = 'absolute';
                    divLayer.style.top = '0';
                    divLayer.style.left = '0';
                    divLayer.style.transform = 'translate(' + (layer.alignment?.offsetX || 0) + 'px, ' + (layer.alignment?.offsetY || 0) + 'px)';
                    divLayer.style.opacity = (layer.opacity || 100) / 100;
                   
                    var img = document.createElement('img');
                    img.style.display = 'block';
                    img.style.transform = 'scale(' + zoomAtual + ')';
                    img.style.transformOrigin = '0 0';
                    img.src = layer.imagePath || '';
                   
                    img.onload = function() {
                        camadasDiv.style.width = this.width + 'px';
                        camadasDiv.style.height = this.height + 'px';
                        log('🖼️ Imagem carregada: ' + this.width + 'x' + this.height, 'info');
                    };
                   
                    img.onerror = function() {
                        this.src = 'data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22800%22 height=%22600%22%3E%3Crect width=%22100%25%22 height=%22100%25%22 fill=%22%23334155%22/%3E%3Ctext x=%2250%25%22 y=%2250%25%22 text-anchor=%22middle%22 fill=%22white%22%3ESem imagem%3C/text%3E%3C/svg%3E';
                        log('⚠️ Imagem não encontrada: ' + layer.imagePath, 'warning');
                    };
                   
                    divLayer.appendChild(img);
                   
                    var markersDiv = document.createElement('div');
                    markersDiv.style.position = 'absolute';
                    markersDiv.style.top = '0';
                    markersDiv.style.left = '0';
                    markersDiv.style.width = '100%';
                    markersDiv.style.height = '100%';
                    markersDiv.style.pointerEvents = 'none';
                   
                    if (layer.markers && layer.markers.length > 0) {
                        log('📍 Renderizando ' + layer.markers.length + ' marcador(es) para camada ' + layer.name, 'info');
                        for (var j = 0; j < layer.markers.length; j++) {
                            var marker = layer.markers[j];
                            var markerDiv = criarMarcador(marker, layer.id);
                            markersDiv.appendChild(markerDiv);
                            marcadores.push({ el: markerDiv, data: marker });
                        }
                     }
                     }
                   
                    divLayer.appendChild(markersDiv);
                    camadasDiv.appendChild(divLayer);
                    camadas.push(divLayer);
                 }
                 }
                  
                 divLayer.appendChild(markersDiv);
                 log('✅ Renderização concluída', 'success');
                camadasDiv.appendChild(divLayer);
                 camadas.push(divLayer);
             }
             }
        }
       
        function criarMarcador(marker, floorId) {
            var div = document.createElement('div');
            div.className = 'mapa-marker';
            div.setAttribute('data-marker-id', marker.id);
            div.setAttribute('data-floor', floorId);
            div.setAttribute('data-x', marker.x);
            div.setAttribute('data-y', marker.y);
            div.style.position = 'absolute';
            div.style.left = (marker.x * zoomAtual) + 'px';
            div.style.top = (marker.y * zoomAtual) + 'px';
            div.style.zIndex = '100';
            div.style.transform = 'translate(-50%, -50%)';
            div.style.cursor = (marker.action && marker.action !== 'none') ? 'pointer' : 'default';
              
              
             function criarMarcador(marker, floorId) {
             var tamanhoIcone = Math.max(20, Math.floor(20 * zoomAtual));
                var div = document.createElement('div');
            var htmlIcone = marker.iconBase64 ? '<img src="' + marker.iconBase64 + '" style="width:' + tamanhoIcone + 'px; height:' + tamanhoIcone + 'px;">' : '<span style="font-size:' + tamanhoIcone + 'px;">📍</span>';
                div.className = 'mapa-marker';
           
                div.setAttribute('data-marker-id', marker.id);
            var textoAcao = '';
                div.setAttribute('data-floor', floorId);
            if (marker.action === 'popup') textoAcao = '📋 Informações';
                div.setAttribute('data-x', marker.x);
            else if (marker.action === 'nextFloor') textoAcao = '⬆️ Próximo andar';
                div.setAttribute('data-y', marker.y);
            else if (marker.action === 'prevFloor') textoAcao = '⬇️ Andar anterior';
                div.style.position = 'absolute';
            else if (marker.action === 'gotoFloor') textoAcao = '🎯 Ir para andar';
                div.style.left = (marker.x * zoomAtual) + 'px';
            else if (marker.action === 'link') textoAcao = '🔗 Link externo';
                div.style.top = (marker.y * zoomAtual) + 'px';
            else textoAcao = '📍 Clique';
                div.style.zIndex = '100';
           
                div.style.transform = 'translate(-50%, -50%)';
            div.innerHTML = '<div style="display:flex; align-items:center; justify-content:center;">' + htmlIcone + '</div>' +
                div.style.cursor = (marker.action && marker.action !== 'none') ? 'pointer' : 'default';
                '<div style="position:absolute; bottom:100%; left:50%; transform:translateX(-50%); background:#1e293b; color:white; padding:4px 8px; border-radius:6px; font-size:10px; white-space:nowrap; opacity:0; visibility:hidden; transition:0.2s; pointer-events:none;">' +
               
                '<strong>' + (marker.name || 'Marcador') + '</strong><br><small>' + textoAcao + '</small></div>' +
                var tamanhoIcone = Math.max(20, Math.floor(20 * zoomAtual));
                '<div style="position:absolute; top:-8px; right:-8px; background:#ef4444; color:white; font-size:9px; min-width:16px; height:16px; border-radius:10px; display:flex; align-items:center; justify-content:center; padding:0 4px; ' + (!marker.hasBadge ? 'display:none;' : '') + '">' + (marker.hasBadge ? (marker.badgeNumber || marker.number || '') : '') + '</div>';
                var htmlIcone = marker.iconBase64 ? '<img src="' + marker.iconBase64 + '" style="width:' + tamanhoIcone + 'px; height:' + tamanhoIcone + 'px;">' : '<span style="font-size:' + tamanhoIcone + 'px;">📍</span>';
           
               
            div.addEventListener('mouseenter', function() { this.style.transform = 'translate(-50%, -50%) scale(1.15)'; var tp = this.children[1]; if (tp) { tp.style.opacity = '1'; tp.style.visibility = 'visible'; } });
                var textoAcao = '';
            div.addEventListener('mouseleave', function() { this.style.transform = 'translate(-50%, -50%) scale(1)'; var tp = this.children[1]; if (tp) { tp.style.opacity = '0'; tp.style.visibility = 'hidden'; } });
                if (marker.action === 'popup') textoAcao = '📋 Informações';
           
                else if (marker.action === 'nextFloor') textoAcao = '⬆️ Próximo andar';
            if (marker.action && marker.action !== 'none') {
                else if (marker.action === 'prevFloor') textoAcao = '⬇️ Andar anterior';
                div.addEventListener('click', function(e) {
                else if (marker.action === 'gotoFloor') textoAcao = '🎯 Ir para andar';
                    e.stopPropagation();
                else if (marker.action === 'link') textoAcao = '🔗 Link externo';
                    if (marker.action === 'popup') alert(marker.name + '\n\n' + (marker.actionData?.text || 'Sem informações'));
                else textoAcao = '📍 Clique';
                    else if (marker.action === 'nextFloor') irProximoAndar();
               
                    else if (marker.action === 'prevFloor') irAndarAnterior();
                div.innerHTML = '<div style="display:flex; align-items:center; justify-content:center;">' + htmlIcone + '</div>' +
                    else if (marker.action === 'gotoFloor' && marker.actionData?.floorId !== undefined) irParaAndar(marker.actionData.floorId);
                    '<div style="position:absolute; bottom:100%; left:50%; transform:translateX(-50%); background:#1e293b; color:white; padding:4px 8px; border-radius:6px; font-size:10px; white-space:nowrap; opacity:0; visibility:hidden; transition:0.2s; pointer-events:none;">' +
                    else if (marker.action === 'link' && marker.actionData?.url && marker.actionData.url !== '#') window.open(marker.actionData.url, marker.actionData.target || '_blank');
                    '<strong>' + (marker.name || 'Marcador') + '</strong><br><small>' + textoAcao + '</small></div>' +
                });
                    '<div style="position:absolute; top:-8px; right:-8px; background:#ef4444; color:white; font-size:9px; min-width:16px; height:16px; border-radius:10px; display:flex; align-items:center; justify-content:center; padding:0 4px; ' + (!marker.hasBadge ? 'display:none;' : '') + '">' + (marker.hasBadge ? (marker.badgeNumber || marker.number || '') : '') + '</div>';
               
                div.addEventListener('mouseenter', function() { this.style.transform = 'translate(-50%, -50%) scale(1.15)'; var tp = this.children[1]; if (tp) { tp.style.opacity = '1'; tp.style.visibility = 'visible'; } });
                div.addEventListener('mouseleave', function() { this.style.transform = 'translate(-50%, -50%) scale(1)'; var tp = this.children[1]; if (tp) { tp.style.opacity = '0'; tp.style.visibility = 'hidden'; } });
               
                if (marker.action && marker.action !== 'none') {
                    div.addEventListener('click', function(e) {
                        e.stopPropagation();
                        if (marker.action === 'popup') alert(marker.name + '\n\n' + (marker.actionData?.text || 'Sem informações'));
                        else if (marker.action === 'nextFloor') irProximoAndar();
                        else if (marker.action === 'prevFloor') irAndarAnterior();
                        else if (marker.action === 'gotoFloor' && marker.actionData?.floorId !== undefined) irParaAndar(marker.actionData.floorId);
                        else if (marker.action === 'link' && marker.actionData?.url && marker.actionData.url !== '#') window.open(marker.actionData.url, marker.actionData.target || '_blank');
                    });
                }
                return div;
             }
             }
              
             return div;
            function atualizarPosicaoMarcadores() {
        }
                for (var i = 0; i < marcadores.length; i++) {
       
                    var item = marcadores[i];
        function atualizarPosicaoMarcadores() {
                    if (parseInt(item.el.getAttribute('data-floor')) === andarAtual) {
            for (var i = 0; i < marcadores.length; i++) {
                        item.el.style.left = (item.data.x * zoomAtual) + 'px';
                var item = marcadores[i];
                        item.el.style.top = (item.data.y * zoomAtual) + 'px';
                if (parseInt(item.el.getAttribute('data-floor')) === andarAtual) {
                        var ts = Math.max(20, Math.floor(20 * zoomAtual));
                    item.el.style.left = (item.data.x * zoomAtual) + 'px';
                        var idiv = item.el.children[0];
                    item.el.style.top = (item.data.y * zoomAtual) + 'px';
                        if (idiv) {
                    var ts = Math.max(20, Math.floor(20 * zoomAtual));
                            if (item.data.iconBase64) idiv.innerHTML = '<img src="' + item.data.iconBase64 + '" style="width:' + ts + 'px; height:' + ts + 'px;">';
                    var idiv = item.el.children[0];
                            else idiv.innerHTML = '<span style="font-size:' + ts + 'px;">📍</span>';
                    if (idiv) {
                        }
                        if (item.data.iconBase64) idiv.innerHTML = '<img src="' + item.data.iconBase64 + '" style="width:' + ts + 'px; height:' + ts + 'px;">';
                        else idiv.innerHTML = '<span style="font-size:' + ts + 'px;">📍</span>';
                     }
                     }
                 }
                 }
             }
             }
           
        }
            function irProximoAndar() {
       
                var idx = -1;
        function irProximoAndar() {
                for (var i = 0; i < config.layers.length; i++) {
            var idx = -1;
                    if (config.layers[i].id === andarAtual) idx = i;
            for (var i = 0; i < config.layers.length; i++) {
                }
                if (config.layers[i].id === andarAtual) idx = i;
                if (idx < config.layers.length - 1) {
                    irParaAndar(config.layers[idx + 1].id);
                    log('⬆️ Mudando para próximo andar: ' + config.layers[idx + 1].name, 'info');
                }
             }
             }
              
             if (idx < config.layers.length - 1) irParaAndar(config.layers[idx + 1].id);
            function irAndarAnterior() {
        }
                var idx = -1;
       
                for (var i = 0; i < config.layers.length; i++) {
        function irAndarAnterior() {
                    if (config.layers[i].id === andarAtual) idx = i;
            var idx = -1;
                }
            for (var i = 0; i < config.layers.length; i++) {
                if (idx > 0) {
                if (config.layers[i].id === andarAtual) idx = i;
                    irParaAndar(config.layers[idx - 1].id);
                    log('⬇️ Mudando para andar anterior: ' + config.layers[idx - 1].name, 'info');
                }
             }
             }
              
             if (idx > 0) irParaAndar(config.layers[idx - 1].id);
            function irParaAndar(floorId) {
        }
                andarAtual = floorId;
       
                for (var i = 0; i < camadas.length; i++) {
        function irParaAndar(floorId) {
                    var lf = parseInt(camadas[i].getAttribute('data-floor'));
            andarAtual = floorId;
                    camadas[i].style.display = lf === floorId ? 'block' : 'none';
            for (var i = 0; i < camadas.length; i++) {
                }
                var lf = parseInt(camadas[i].getAttribute('data-floor'));
                var fd = null;
                camadas[i].style.display = lf === floorId ? 'block' : 'none';
                for (var i = 0; i < config.layers.length; i++) {
                    if (config.layers[i].id === floorId) fd = config.layers[i];
                }
                var nomeSpan = document.getElementById('floor-name-' + id);
                if (nomeSpan && fd) nomeSpan.textContent = fd.name;
                atualizarPosicaoMarcadores();
             }
             }
              
             var fd = null;
             function zoomIn() {
             for (var i = 0; i < config.layers.length; i++) {
                 if (zoomAtual < zoomMax) {
                 if (config.layers[i].id === floorId) fd = config.layers[i];
                    var old = zoomAtual;
                    zoomAtual = Math.min(zoomAtual + zoomPasso, zoomMax);
                    aplicarZoom(old);
                    log('🔍 Zoom in: ' + Math.round(zoomAtual * 100) + '%', 'info');
                }
             }
             }
              
             var nomeSpan = document.getElementById('floor-name-' + id);
             function zoomOut() {
            if (nomeSpan && fd) nomeSpan.textContent = fd.name;
                if (zoomAtual > zoomMin) {
             atualizarPosicaoMarcadores();
                    var old = zoomAtual;
        }
                    zoomAtual = Math.max(zoomAtual - zoomPasso, zoomMin);
       
                    aplicarZoom(old);
        function zoomIn() {
                    log('🔍 Zoom out: ' + Math.round(zoomAtual * 100) + '%', 'info');
            if (zoomAtual < zoomMax) {
                }
                var old = zoomAtual;
                zoomAtual = Math.min(zoomAtual + zoomPasso, zoomMax);
                aplicarZoom(old);
             }
             }
           
        }
            function aplicarZoom(oldZoom) {
       
                var imgs = document.querySelectorAll('.mapa-image');
        function zoomOut() {
                for (var i = 0; i < imgs.length; i++) imgs[i].style.transform = 'scale(' + zoomAtual + ')';
            if (zoomAtual > zoomMin) {
                 var rect = viewport.getBoundingClientRect();
                 var old = zoomAtual;
                var cx = rect.width / 2, cy = rect.height / 2;
                 zoomAtual = Math.max(zoomAtual - zoomPasso, zoomMin);
                var sx = (viewport.scrollLeft + cx) / oldZoom, sy = (viewport.scrollTop + cy) / oldZoom;
                 aplicarZoom(old);
                viewport.scrollLeft = sx * zoomAtual - cx;
                 viewport.scrollTop = sy * zoomAtual - cy;
                atualizarPosicaoMarcadores();
                var zoomSpan = document.getElementById('zoom-level-' + id);
                 if (zoomSpan) zoomSpan.textContent = Math.round(zoomAtual * 100) + '%';
             }
             }
           
            function resetarView() {
                zoomAtual = config.mapConfig?.defaultZoom || 1;
                var imgs = document.querySelectorAll('.mapa-image');
                for (var i = 0; i < imgs.length; i++) imgs[i].style.transform = 'scale(' + zoomAtual + ')';
                viewport.scrollLeft = 0;
                viewport.scrollTop = 0;
                atualizarPosicaoMarcadores();
                var zoomSpan = document.getElementById('zoom-level-' + id);
                if (zoomSpan) zoomSpan.textContent = Math.round(zoomAtual * 100) + '%';
                log('⟳ Visualização resetada', 'info');
            }
           
            // Conectar botões
            document.getElementById('zoom-in-' + id).addEventListener('click', zoomIn);
            document.getElementById('zoom-out-' + id).addEventListener('click', zoomOut);
            document.getElementById('reset-' + id).addEventListener('click', resetarView);
            document.getElementById('prev-' + id).addEventListener('click', irAndarAnterior);
            document.getElementById('next-' + id).addEventListener('click', irProximoAndar);
           
            // Arrastar
            viewport.addEventListener('mousedown', function(e) {
                if (e.target.closest('.mapa-marker')) return;
                arrastando = true;
                arrasteInicio = { x: e.clientX, y: e.clientY, scrollLeft: viewport.scrollLeft, scrollTop: viewport.scrollTop };
                viewport.style.cursor = 'grabbing';
                e.preventDefault();
            });
           
            window.addEventListener('mousemove', function(e) {
                if (!arrastando) return;
                viewport.scrollLeft = arrasteInicio.scrollLeft - (e.clientX - arrasteInicio.x);
                viewport.scrollTop = arrasteInicio.scrollTop - (e.clientY - arrasteInicio.y);
            });
           
            window.addEventListener('mouseup', function() { arrastando = false; viewport.style.cursor = 'grab'; });
           
            // Zoom com scroll
            viewport.addEventListener('wheel', function(e) {
                if (e.ctrlKey) { e.preventDefault(); e.deltaY < 0 ? zoomIn() : zoomOut(); }
            });
           
            // Coordenadas
            viewport.addEventListener('mousemove', function(e) {
                var rect = viewport.getBoundingClientRect();
                var x = (e.clientX - rect.left + viewport.scrollLeft) / zoomAtual;
                var y = (e.clientY - rect.top + viewport.scrollTop) / zoomAtual;
                coordsDiv.textContent = '📍 ' + Math.round(x) + ', ' + Math.round(y) + ' | ' + Math.round(zoomAtual * 100) + '%';
            });
           
            renderizarCamadas();
            log('🎉 Visualizador iniciado com sucesso!', 'success');
           
        } catch(e) {
            log('❌ ERRO NO VISUALIZADOR: ' + e.message, 'error');
            container.innerHTML = '<div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); text-align:center; color:#ef4444;">❌ Erro no visualizador<br><small>' + e.message + '</small></div>';
         }
         }
       
        function aplicarZoom(oldZoom) {
            var imgs = document.querySelectorAll('.mapa-image');
            for (var i = 0; i < imgs.length; i++) imgs[i].style.transform = 'scale(' + zoomAtual + ')';
            var rect = viewport.getBoundingClientRect();
            var cx = rect.width / 2, cy = rect.height / 2;
            var sx = (viewport.scrollLeft + cx) / oldZoom, sy = (viewport.scrollTop + cy) / oldZoom;
            viewport.scrollLeft = sx * zoomAtual - cx;
            viewport.scrollTop = sy * zoomAtual - cy;
            atualizarPosicaoMarcadores();
            var zoomSpan = document.getElementById('zoom-level-' + id);
            if (zoomSpan) zoomSpan.textContent = Math.round(zoomAtual * 100) + '%';
        }
       
        function resetarView() {
            zoomAtual = config.mapConfig.defaultZoom || 1;
            var imgs = document.querySelectorAll('.mapa-image');
            for (var i = 0; i < imgs.length; i++) imgs[i].style.transform = 'scale(' + zoomAtual + ')';
            viewport.scrollLeft = 0;
            viewport.scrollTop = 0;
            atualizarPosicaoMarcadores();
            var zoomSpan = document.getElementById('zoom-level-' + id);
            if (zoomSpan) zoomSpan.textContent = Math.round(zoomAtual * 100) + '%';
        }
       
        // Conectar botões
        document.getElementById('zoom-in-' + id).addEventListener('click', zoomIn);
        document.getElementById('zoom-out-' + id).addEventListener('click', zoomOut);
        document.getElementById('reset-' + id).addEventListener('click', resetarView);
        document.getElementById('prev-' + id).addEventListener('click', irAndarAnterior);
        document.getElementById('next-' + id).addEventListener('click', irProximoAndar);
       
        // Arrastar
        viewport.addEventListener('mousedown', function(e) {
            if (e.target.closest('.mapa-marker')) return;
            arrastando = true;
            arrasteInicio = { x: e.clientX, y: e.clientY, scrollLeft: viewport.scrollLeft, scrollTop: viewport.scrollTop };
            viewport.style.cursor = 'grabbing';
            e.preventDefault();
        });
       
        window.addEventListener('mousemove', function(e) {
            if (!arrastando) return;
            viewport.scrollLeft = arrasteInicio.scrollLeft - (e.clientX - arrasteInicio.x);
            viewport.scrollTop = arrasteInicio.scrollTop - (e.clientY - arrasteInicio.y);
        });
       
        window.addEventListener('mouseup', function() { arrastando = false; viewport.style.cursor = 'grab'; });
       
        viewport.addEventListener('wheel', function(e) {
            if (e.ctrlKey) { e.preventDefault(); e.deltaY < 0 ? zoomIn() : zoomOut(); }
        });
       
        viewport.addEventListener('mousemove', function(e) {
            var rect = viewport.getBoundingClientRect();
            var x = (e.clientX - rect.left + viewport.scrollLeft) / zoomAtual;
            var y = (e.clientY - rect.top + viewport.scrollTop) / zoomAtual;
            coordsDiv.textContent = '📍 ' + Math.round(x) + ', ' + Math.round(y) + ' | ' + Math.round(zoomAtual * 100) + '%';
        });
       
        renderizarCamadas();
     }
     }
})();
})();
</script></includeonly>
</script></includeonly>

Edição atual tal como às 20h38min de 9 de abril de 2026