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

De Wiki Gla
Ir para navegação Ir para pesquisar
Linha 1: Linha 1:
<includeonly><div id="mapa-viewer-{{{id|mapa1}}}" class="mapa-container" style="width:{{{largura|100%}}}; height:{{{altura|500px}}}; background:#0f172a; border-radius:12px; overflow:hidden; position:relative;">
<includeonly>{{#tag:pre|{{{json}}}|style=display:none|id=mapa-json-{{{id}}}}}
<div id="mapa-viewer-{{{id|mapa1}}}" style="width:{{{largura|100%}}}; height:{{{altura|500px}}}; background:#0f172a; border-radius:12px; overflow:hidden; position:relative;">
     <div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); color:#64748b; text-align:center;">
     <div style="position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); color:#64748b; text-align:center;">
         <div>🗺️ Carregando mapa...</div>
         <div>🗺️ Carregando mapa...</div>
Linha 11: Linha 12:
     var containerId = 'mapa-viewer-{{{id|mapa1}}}';
     var containerId = 'mapa-viewer-{{{id|mapa1}}}';
     var container = document.getElementById(containerId);
     var container = document.getElementById(containerId);
    var jsonId = 'mapa-json-{{{id|mapa1}}}';
    var preElement = document.getElementById(jsonId);
   
     if (!container) return;
     if (!container) return;
    if (!preElement) {
        container.innerHTML = '<div style="padding:20px; text-align:center; color:#ef4444;">❌ Dados do mapa não encontrados</div>';
        return;
    }
   
    // Pegar o JSON do pre escondido
    var jsonString = preElement.textContent || preElement.innerText;
   
    if (!jsonString || jsonString.trim() === '') {
        container.innerHTML = '<div style="padding:20px; text-align:center; color:#ef4444;">❌ Configuração vazia</div>';
        return;
    }
      
      
    // Receber configuração do template
    var configJSON = `{{{json}}}`;
    console.log(configJSON );
     var mapConfig;
     var mapConfig;
   
     try {
     try {
         mapConfig = JSON.parse(configJSON);
         mapConfig = JSON.parse(jsonString);
     } catch(e) {
     } catch(e) {
         container.innerHTML = '<div style="padding:20px; text-align:center; color:#ef4444;">❌ Erro na configuração do mapa</div>';
         container.innerHTML = '<div style="padding:20px; text-align:center; color:#ef4444;">❌ Erro no JSON: ' + e.message + '</div>';
         console.error('Erro ao parsear JSON:', e);
         console.error('JSON inválido:', jsonString);
        return;
    }
   
    if (!mapConfig.layers || mapConfig.layers.length === 0) {
        container.innerHTML = '<div style="padding:20px; text-align:center; color:#f59e0b;">⚠️ Nenhuma camada configurada</div>';
         return;
         return;
     }
     }
      
      
     // Inicializar o viewer
     // Mapa carregado com sucesso!
     iniciarMapaViewer(containerId, mapConfig);
     iniciarMapaViewer(containerId, mapConfig);
      
      
    // ==================== VIEWER COMPLETO ====================
     function iniciarMapaViewer(containerId, config) {
     function iniciarMapaViewer(containerId, config) {
         var container = document.getElementById(containerId);
         var container = document.getElementById(containerId);
         if (!container) return;
         if (!container) return;
          
          
        // Limpar container
         container.innerHTML = '';
         container.innerHTML = '';
         container.style.position = 'relative';
         container.style.position = 'relative';
         container.style.overflow = 'hidden';
         container.style.overflow = 'hidden';
          
          
         // Criar estrutura do viewer
         // Toolbar superior
         container.innerHTML = `
         var toolbar = document.createElement('div');
            <div style="position:absolute; top:10px; left:10px; right:10px; z-index:100; display:flex; justify-content:space-between; gap:8px; flex-wrap:wrap;">
        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;';
                <div style="display:flex; gap:5px; background:rgba(0,0,0,0.7); padding:5px 10px; border-radius:30px;">
        toolbar.innerHTML = `
                    <button class="mapa-zoom-in" style="background:#334155; border:none; color:white; width:32px; height:32px; border-radius:50%; cursor:pointer; font-size:18px;">+</button>
            <div style="display:flex; gap:5px; background:rgba(0,0,0,0.7); padding:5px 10px; border-radius:30px;">
                    <button class="mapa-zoom-out" style="background:#334155; border:none; color:white; width:32px; height:32px; border-radius:50%; cursor:pointer; font-size:18px;">-</button>
                <button class="mapa-zoom-in" style="background:#334155; border:none; color:white; width:32px; height:32px; border-radius:50%; cursor:pointer;">+</button>
                    <button class="mapa-reset" style="background:#334155; border:none; color:white; width:32px; height:32px; border-radius:50%; cursor:pointer;">⟳</button>
                <button class="mapa-zoom-out" style="background:#334155; border:none; color:white; width:32px; height:32px; border-radius:50%; cursor:pointer;">-</button>
                </div>
                <button class="mapa-reset" style="background:#334155; border:none; color:white; width:32px; height:32px; border-radius:50%; cursor:pointer;">⟳</button>
                <div style="background:rgba(0,0,0,0.7); padding:5px 15px; border-radius:30px; color:white; font-size:12px;">
                    <span class="mapa-floor-name">Carregando...</span>
                </div>
                <div style="background:rgba(0,0,0,0.7); padding:5px 12px; border-radius:30px; color:#a5b4fc; font-size:12px;" class="mapa-zoom-level">100%</div>
             </div>
             </div>
            <div class="mapa-viewport" style="width:100%; height:100%; overflow:auto; cursor:grab; background:#0f172a;">
             <div style="background:rgba(0,0,0,0.7); padding:5px 15px; border-radius:30px; color:white; font-size:12px;">
                <div class="mapa-layers" style="position:relative; min-width:100%; min-height:100%;"></div>
                 <span class="mapa-floor-name">${config.layers[0]?.name || 'Mapa'}</span>
            </div>
            <div style="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;" class="mapa-coords">📍 0, 0</div>
             <div style="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;">
                <button class="mapa-prev-floor" style="background:#334155; border:none; color:white; width:36px; height:36px; border-radius:50%; cursor:pointer; font-size:18px;">▲</button>
                 <button class="mapa-next-floor" style="background:#334155; border:none; color:white; width:36px; height:36px; border-radius:50%; cursor:pointer; font-size:18px;"></button>
             </div>
             </div>
            <div style="background:rgba(0,0,0,0.7); padding:5px 12px; border-radius:30px; color:#a5b4fc; font-size:12px;" class="mapa-zoom-level">100%</div>
        `;
       
        // Viewport
        var viewport = document.createElement('div');
        viewport.className = 'mapa-viewport';
        viewport.style.cssText = 'width:100%; height:100%; overflow:auto; cursor:grab; background:#0f172a;';
       
        var layersContainer = document.createElement('div');
        layersContainer.className = 'mapa-layers';
        layersContainer.style.cssText = 'position:relative; min-width:100%; min-height:100%;';
        viewport.appendChild(layersContainer);
       
        // 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';
       
        // 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 class="mapa-prev-floor" style="background:#334155; border:none; color:white; width:36px; height:36px; border-radius:50%; cursor:pointer;">▲</button>
            <button class="mapa-next-floor" style="background:#334155; border:none; color:white; width:36px; height:36px; border-radius:50%; cursor:pointer;">▼</button>
         `;
         `;
          
          
         // Referências DOM
         container.appendChild(toolbar);
        var viewport = container.querySelector('.mapa-viewport');
         container.appendChild(viewport);
         var layersContainer = container.querySelector('.mapa-layers');
         container.appendChild(coordsDiv);
         var floorNameSpan = container.querySelector('.mapa-floor-name');
         container.appendChild(navDiv);
         var zoomLevelSpan = container.querySelector('.mapa-zoom-level');
          
          
         // Variáveis de estado
         // Variáveis
         var currentZoom = config.mapConfig.defaultZoom || 1;
         var currentZoom = config.mapConfig.defaultZoom || 1;
         var currentFloor = config.mapConfig.initialFloor || 0;
         var currentFloor = config.mapConfig.initialFloor || 0;
Linha 78: Linha 107:
         var isPanning = false;
         var isPanning = false;
         var panStart = { x: 0, y: 0, scrollLeft: 0, scrollTop: 0 };
         var panStart = { x: 0, y: 0, scrollLeft: 0, scrollTop: 0 };
       
        var floorNameSpan = toolbar.querySelector('.mapa-floor-name');
        var zoomLevelSpan = toolbar.querySelector('.mapa-zoom-level');
          
          
         // Renderizar camadas
         // Renderizar camadas
         function renderizarCamadas() {
         function renderizarCamadas() {
            if (!layersContainer) return;
             layersContainer.innerHTML = '';
             layersContainer.innerHTML = '';
             layers = [];
             layers = [];
             markers = [];
             markers = [];
              
              
             if (!config.layers || config.layers.length === 0) {
             // Verificar se o andar atual existe
                 layersContainer.innerHTML = '<div style="text-align:center; color:#64748b; padding:50px;">Nenhuma camada carregada</div>';
            var floorExists = false;
                return;
            for (var i = 0; i < config.layers.length; i++) {
                if (config.layers[i].id === currentFloor) floorExists = true;
            }
            if (!floorExists && config.layers.length > 0) {
                 currentFloor = config.layers[0].id;
             }
             }
              
              
             // Verificar se o andar atual existe
             var floorAtual = null;
             if (!config.layers.find(function(l) { return l.id === currentFloor; })) {
             for (var i = 0; i < config.layers.length; i++) {
                currentFloor = config.layers[0]?.id || 0;
                if (config.layers[i].id === currentFloor) floorAtual = config.layers[i];
             }
             }
           
            var floorAtual = config.layers.find(function(l) { return l.id === currentFloor; });
             if (floorAtual && floorNameSpan) {
             if (floorAtual && floorNameSpan) {
                 floorNameSpan.textContent = floorAtual.name;
                 floorNameSpan.textContent = floorAtual.name;
             }
             }
              
              
            // Percorrer camadas
             for (var i = 0; i < config.layers.length; i++) {
             for (var i = 0; i < config.layers.length; i++) {
                 var layer = config.layers[i];
                 var layer = config.layers[i];
Linha 115: Linha 147:
                  
                  
                 var img = document.createElement('img');
                 var img = document.createElement('img');
                img.className = 'mapa-image';
                 img.style.display = 'block';
                 img.style.display = 'block';
                 img.style.transform = 'scale(' + currentZoom + ')';
                 img.style.transform = 'scale(' + currentZoom + ')';
Linha 121: Linha 152:
                 img.src = layer.imagePath || '';
                 img.src = layer.imagePath || '';
                  
                  
                 img.onload = (function(img, layersContainer) {
                 img.onload = function() {
                     return function() {
                     layersContainer.style.width = this.width + 'px';
                        layersContainer.style.width = this.width + 'px';
                    layersContainer.style.height = this.height + 'px';
                        layersContainer.style.height = this.height + 'px';
                 };
                    };
                 })(img, layersContainer);
                  
                  
                 img.onerror = (function(layer, img) {
                 img.onerror = function() {
                     return function() {
                     var canvas = document.createElement('canvas');
                        var canvas = document.createElement('canvas');
                    canvas.width = 800;
                        canvas.width = 800;
                    canvas.height = 600;
                        canvas.height = 600;
                    var ctx = canvas.getContext('2d');
                        var ctx = canvas.getContext('2d');
                    ctx.fillStyle = '#334155';
                        var cores = ['#4CAF50', '#2196F3', '#FF9800', '#9C27B0'];
                    ctx.fillRect(0, 0, canvas.width, canvas.height);
                        ctx.fillStyle = cores[layer.id % cores.length];
                    ctx.fillStyle = 'white';
                        ctx.fillRect(0, 0, canvas.width, canvas.height);
                    ctx.font = '20px Arial';
                        ctx.fillStyle = 'white';
                    ctx.fillText(layer.name || 'Andar', 50, 100);
                        ctx.font = 'bold 24px Arial';
                    this.src = canvas.toDataURL();
                        ctx.fillText(layer.name || 'Andar ' + (layer.id + 1), 50, 100);
                 };
                        ctx.fillStyle = '#e0e0e0';
                        ctx.font = '14px Arial';
                        ctx.fillText('Clique em "Escolher imagem" no editor', 50, 150);
                        img.src = canvas.toDataURL();
                    };
                 })(layer, img);
                  
                  
                 divLayer.appendChild(img);
                 divLayer.appendChild(img);
Linha 157: Linha 180:
                 markersDiv.style.pointerEvents = 'none';
                 markersDiv.style.pointerEvents = 'none';
                  
                  
                 if (layer.markers && layer.markers.length > 0) {
                 if (layer.markers) {
                     for (var j = 0; j < layer.markers.length; j++) {
                     for (var j = 0; j < layer.markers.length; j++) {
                         var marker = layer.markers[j];
                         var marker = layer.markers[j];
Linha 172: Linha 195:
         }
         }
          
          
        // Criar marcador
         function criarMarcador(marker, floorId) {
         function criarMarcador(marker, floorId) {
             var div = document.createElement('div');
             var div = document.createElement('div');
Linha 186: Linha 208:
             div.style.zIndex = '100';
             div.style.zIndex = '100';
             div.style.transform = 'translate(-50%, -50%)';
             div.style.transform = 'translate(-50%, -50%)';
              
             div.style.cursor = (marker.action && marker.action !== 'none') ? 'pointer' : 'default';
            // Cursor baseado na ação
            var temAcao = marker.action && marker.action !== 'none';
            div.style.cursor = temAcao ? 'pointer' : 'default';
              
              
             var tamanhoIcone = Math.max(20, Math.floor(20 * currentZoom));
             var tamanhoIcone = Math.max(20, Math.floor(20 * currentZoom));
             var htmlIcone;
             var htmlIcone = marker.iconBase64 ?
           
                 '<img src="' + marker.iconBase64 + '" style="width:' + tamanhoIcone + 'px; height:' + tamanhoIcone + 'px;">' :
            if (marker.iconBase64) {
                 '<span style="font-size:' + tamanhoIcone + 'px;">📍</span>';
                 htmlIcone = '<img src="' + marker.iconBase64 + '" style="width:' + tamanhoIcone + 'px; height:' + tamanhoIcone + 'px;">';
            } else {
                 htmlIcone = '<span style="font-size:' + tamanhoIcone + 'px;">📍</span>';
            }
              
              
             var textoAcao = '';
             var textoAcao = '';
Linha 212: Linha 227:
             div.innerHTML = `
             div.innerHTML = `
                 <div style="display:flex; align-items:center; justify-content:center;">${htmlIcone}</div>
                 <div style="display:flex; align-items:center; justify-content:center;">${htmlIcone}</div>
                 <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; z-index:101;">
                 <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>
                     <strong>${marker.name || 'Marcador'}</strong><br>
                     <small>${textoAcao}</small>
                     <small>${textoAcao}</small>
Linha 219: Linha 234:
             `;
             `;
              
              
            // Evento hover
             div.addEventListener('mouseenter', function() {
             div.addEventListener('mouseenter', function() {
                 this.style.transform = 'translate(-50%, -50%) scale(1.15)';
                 this.style.transform = 'translate(-50%, -50%) scale(1.15)';
Linha 238: Linha 252:
             });
             });
              
              
            // Evento clique
             if (marker.action && marker.action !== 'none') {
             if (temAcao) {
                 div.addEventListener('click', function(e) {
                 div.addEventListener('click', function(e) {
                     e.stopPropagation();
                     e.stopPropagation();
Linha 249: Linha 262:
         }
         }
          
          
        // Executar ação do marcador
         function executarAcao(marker) {
         function executarAcao(marker) {
             switch(marker.action) {
             switch(marker.action) {
                 case 'popup':
                 case 'popup':
                    var popupText = marker.actionData?.text || 'Sem informações';
                     alert(marker.name + '\n\n' + (marker.actionData?.text || 'Sem informações'));
                     alert(marker.name + '\n\n' + popupText);
                     break;
                     break;
                 case 'nextFloor':
                 case 'nextFloor':
Linha 275: Linha 286:
         }
         }
          
          
        // Navegação
         function proximoAndar() {
         function proximoAndar() {
             var idx = -1;
             var idx = -1;
             for (var i = 0; i < config.layers.length; i++) {
             for (var i = 0; i < config.layers.length; i++) {
                 if (config.layers[i].id === currentFloor) {
                 if (config.layers[i].id === currentFloor) idx = i;
                    idx = i;
                    break;
                }
             }
             }
             if (idx < config.layers.length - 1) {
             if (idx < config.layers.length - 1) {
Linha 292: Linha 299:
             var idx = -1;
             var idx = -1;
             for (var i = 0; i < config.layers.length; i++) {
             for (var i = 0; i < config.layers.length; i++) {
                 if (config.layers[i].id === currentFloor) {
                 if (config.layers[i].id === currentFloor) idx = i;
                    idx = i;
                    break;
                }
             }
             }
             if (idx > 0) {
             if (idx > 0) {
Linha 304: Linha 308:
         function irParaAndar(floorId) {
         function irParaAndar(floorId) {
             currentFloor = floorId;
             currentFloor = floorId;
           
             for (var i = 0; i < layers.length; i++) {
             for (var i = 0; i < layers.length; i++) {
                 var layer = layers[i];
                 var layerFloor = parseInt(layers[i].getAttribute('data-floor'));
                var layerFloor = parseInt(layer.getAttribute('data-floor'));
                 layers[i].style.display = layerFloor === floorId ? 'block' : 'none';
                 layer.style.display = layerFloor === floorId ? 'block' : 'none';
             }
             }
           
             var floorData = null;
             var floorData = null;
             for (var i = 0; i < config.layers.length; i++) {
             for (var i = 0; i < config.layers.length; i++) {
                 if (config.layers[i].id === floorId) {
                 if (config.layers[i].id === floorId) floorData = config.layers[i];
                    floorData = config.layers[i];
                    break;
                }
            }
            if (floorData && floorNameSpan) {
                floorNameSpan.textContent = floorData.name;
             }
             }
              
             if (floorData && floorNameSpan) floorNameSpan.textContent = floorData.name;
             atualizarPosicaoMarkers();
             atualizarPosicaoMarkers();
         }
         }
          
          
        // Atualizar posição dos marcadores
         function atualizarPosicaoMarkers() {
         function atualizarPosicaoMarkers() {
             for (var i = 0; i < markers.length; i++) {
             for (var i = 0; i < markers.length; i++) {
Linha 332: Linha 326:
                     item.el.style.left = (item.data.x * currentZoom) + 'px';
                     item.el.style.left = (item.data.x * currentZoom) + 'px';
                     item.el.style.top = (item.data.y * currentZoom) + 'px';
                     item.el.style.top = (item.data.y * currentZoom) + 'px';
                   
                     var tamanhoIcone = Math.max(20, Math.floor(20 * currentZoom));
                     var tamanhoIcone = Math.max(20, Math.floor(20 * currentZoom));
                     var iconDiv = item.el.children[0];
                     var iconDiv = item.el.children[0];
Linha 346: Linha 339:
         }
         }
          
          
        // Zoom
         function zoomIn() {
         function zoomIn() {
             if (currentZoom < maxZoom) {
             if (currentZoom < maxZoom) {
Linha 368: Linha 360:
                 images[i].style.transform = 'scale(' + currentZoom + ')';
                 images[i].style.transform = 'scale(' + currentZoom + ')';
             }
             }
           
             var rect = viewport.getBoundingClientRect();
             var rect = viewport.getBoundingClientRect();
             var cx = rect.width / 2;
             var cx = rect.width / 2, cy = rect.height / 2;
            var cy = rect.height / 2;
             var sx = (viewport.scrollLeft + cx) / oldZoom;
             var sx = (viewport.scrollLeft + cx) / oldZoom;
             var sy = (viewport.scrollTop + cy) / oldZoom;
             var sy = (viewport.scrollTop + cy) / oldZoom;
           
             viewport.scrollLeft = sx * currentZoom - cx;
             viewport.scrollLeft = sx * currentZoom - cx;
             viewport.scrollTop = sy * currentZoom - cy;
             viewport.scrollTop = sy * currentZoom - cy;
           
             atualizarPosicaoMarkers();
             atualizarPosicaoMarkers();
             if (zoomLevelSpan) {
             if (zoomLevelSpan) zoomLevelSpan.textContent = Math.round(currentZoom * 100) + '%';
                zoomLevelSpan.textContent = Math.round(currentZoom * 100) + '%';
            }
         }
         }
          
          
Linha 393: Linha 379:
             viewport.scrollTop = 0;
             viewport.scrollTop = 0;
             atualizarPosicaoMarkers();
             atualizarPosicaoMarkers();
             if (zoomLevelSpan) {
             if (zoomLevelSpan) zoomLevelSpan.textContent = Math.round(currentZoom * 100) + '%';
                zoomLevelSpan.textContent = Math.round(currentZoom * 100) + '%';
            }
         }
         }
          
          
         // Configurar eventos dos botões
         // Eventos dos botões
         var btnZoomIn = container.querySelector('.mapa-zoom-in');
         toolbar.querySelector('.mapa-zoom-in')?.addEventListener('click', zoomIn);
        var btnZoomOut = container.querySelector('.mapa-zoom-out');
         toolbar.querySelector('.mapa-zoom-out')?.addEventListener('click', zoomOut);
         var btnReset = container.querySelector('.mapa-reset');
         toolbar.querySelector('.mapa-reset')?.addEventListener('click', resetarView);
        var btnPrev = container.querySelector('.mapa-prev-floor');
         navDiv.querySelector('.mapa-prev-floor')?.addEventListener('click', andarAnterior);
         var btnNext = container.querySelector('.mapa-next-floor');
         navDiv.querySelector('.mapa-next-floor')?.addEventListener('click', proximoAndar);
       
        if (btnZoomIn) btnZoomIn.addEventListener('click', zoomIn);
         if (btnZoomOut) btnZoomOut.addEventListener('click', zoomOut);
        if (btnReset) btnReset.addEventListener('click', resetarView);
         if (btnPrev) btnPrev.addEventListener('click', andarAnterior);
        if (btnNext) btnNext.addEventListener('click', proximoAndar);
          
          
         // Eventos de pan (arrastar)
         // Pan
         viewport.addEventListener('mousedown', function(e) {
         viewport.addEventListener('mousedown', function(e) {
             if (e.target.closest('.mapa-marker')) return;
             if (e.target.closest('.mapa-marker')) return;
             isPanning = true;
             isPanning = true;
             panStart = {
             panStart = { x: e.clientX, y: e.clientY, scrollLeft: viewport.scrollLeft, scrollTop: viewport.scrollTop };
                x: e.clientX,
                y: e.clientY,
                scrollLeft: viewport.scrollLeft,
                scrollTop: viewport.scrollTop
            };
             viewport.style.cursor = 'grabbing';
             viewport.style.cursor = 'grabbing';
             e.preventDefault();
             e.preventDefault();
Linha 440: Linha 413:
             if (e.ctrlKey) {
             if (e.ctrlKey) {
                 e.preventDefault();
                 e.preventDefault();
                 if (e.deltaY < 0) {
                 e.deltaY < 0 ? zoomIn() : zoomOut();
                    zoomIn();
                } else {
                    zoomOut();
                }
             }
             }
         });
         });
          
          
         // Tracking de coordenadas
         // Tracking coordenadas
         viewport.addEventListener('mousemove', function(e) {
         viewport.addEventListener('mousemove', function(e) {
             var rect = viewport.getBoundingClientRect();
             var rect = viewport.getBoundingClientRect();
             var x = (e.clientX - rect.left + viewport.scrollLeft) / currentZoom;
             var x = (e.clientX - rect.left + viewport.scrollLeft) / currentZoom;
             var y = (e.clientY - rect.top + viewport.scrollTop) / currentZoom;
             var y = (e.clientY - rect.top + viewport.scrollTop) / currentZoom;
             var coordsDiv = container.querySelector('.mapa-coords');
             coordsDiv.textContent = '📍 ' + Math.round(x) + ', ' + Math.round(y) + ' | ' + Math.round(currentZoom * 100) + '%';
            if (coordsDiv) {
                coordsDiv.textContent = '📍 ' + Math.round(x) + ', ' + Math.round(y) + ' | ' + Math.round(currentZoom * 100) + '%';
            }
         });
         });
          
          
        // Inicializar
         renderizarCamadas();
         renderizarCamadas();
     }
     }
})();
})();
</script></includeonly>
</script></includeonly>

Edição das 10h16min de 8 de abril de 2026