Mudanças entre as edições de "Widget:MapaViewer"
Ir para navegação
Ir para pesquisar
| Linha 1: | Linha 1: | ||
<includeonly><div id="mapa-viewer-{ | <includeonly><div id="mapa-viewer-<!--{$id|escape:'quotes'|default:'mapa-default'}-->" style="width: <!--{$largura|escape:'quotes'|default:'100%'}-->; height: <!--{$altura|escape:'quotes'|default:'500px'}-->;"></div> | ||
<script> | <script> | ||
(function() { | (function() { | ||
// Classe MapaViewer | // Classe MapaViewer completa | ||
class MapaViewer { | class MapaViewer { | ||
constructor(containerId, configOrUrl) { | constructor(containerId, configOrUrl) { | ||
| Linha 27: | Linha 27: | ||
if (typeof configOrUrl === 'string') { | if (typeof configOrUrl === 'string') { | ||
if (configOrUrl.startsWith('http | if (configOrUrl.startsWith('http')) { | ||
this.loadJSON(configOrUrl); | this.loadJSON(configOrUrl); | ||
} else { | } else { | ||
| Linha 48: | Linha 48: | ||
this.viewport = document.createElement('div'); | this.viewport = document.createElement('div'); | ||
this.viewport.style.cssText = | this.viewport.style.cssText = 'width:100%;height:100%;overflow:hidden;cursor:grab;position:relative;'; | ||
this.layersContainer = document.createElement('div'); | this.layersContainer = document.createElement('div'); | ||
this.layersContainer.style.cssText = | this.layersContainer.style.cssText = 'position:relative;min-width:100%;min-height:100%;'; | ||
this.viewport.appendChild(this.layersContainer); | this.viewport.appendChild(this.layersContainer); | ||
| Linha 175: | Linha 165: | ||
this.layers = []; | this.layers = []; | ||
this.markers = []; | this.markers = []; | ||
this.config.layers.forEach((layer) => { | this.config.layers.forEach((layer) => { | ||
const $layer = document.createElement('div'); | const $layer = document.createElement('div'); | ||
| Linha 185: | Linha 176: | ||
$layer.style.transform = `translate(${layer.offsetX}px, ${layer.offsetY}px)`; | $layer.style.transform = `translate(${layer.offsetX}px, ${layer.offsetY}px)`; | ||
$layer.style.opacity = (layer.opacity || 100) / 100; | $layer.style.opacity = (layer.opacity || 100) / 100; | ||
const $img = document.createElement('img'); | const $img = document.createElement('img'); | ||
$img.className = 'mapa-image'; | $img.className = 'mapa-image'; | ||
| Linha 192: | Linha 184: | ||
$img.style.pointerEvents = 'none'; | $img.style.pointerEvents = 'none'; | ||
$img.src = layer.imageUrl || ''; | $img.src = layer.imageUrl || ''; | ||
$img.onerror = () => { | $img.onerror = () => { | ||
const canvas = document.createElement('canvas'); | const canvas = document.createElement('canvas'); | ||
| Linha 204: | Linha 197: | ||
$img.src = canvas.toDataURL(); | $img.src = canvas.toDataURL(); | ||
}; | }; | ||
$img.onload = () => { | $img.onload = () => { | ||
this.layersContainer.style.width = `${$img.width}px`; | this.layersContainer.style.width = `${$img.width}px`; | ||
| Linha 209: | Linha 203: | ||
this.centerMap(); | this.centerMap(); | ||
}; | }; | ||
$layer.appendChild($img); | $layer.appendChild($img); | ||
const $markersContainer = document.createElement('div'); | const $markersContainer = document.createElement('div'); | ||
$markersContainer.style.position = 'absolute'; | $markersContainer.style.position = 'absolute'; | ||
| Linha 217: | Linha 213: | ||
$markersContainer.style.height = '100%'; | $markersContainer.style.height = '100%'; | ||
$markersContainer.style.pointerEvents = 'none'; | $markersContainer.style.pointerEvents = 'none'; | ||
if (layer.markers && layer.markers.length) { | if (layer.markers && layer.markers.length) { | ||
layer.markers.forEach(marker => { | layer.markers.forEach(marker => { | ||
| Linha 224: | Linha 221: | ||
}); | }); | ||
} | } | ||
$layer.appendChild($markersContainer); | $layer.appendChild($markersContainer); | ||
this.layersContainer.appendChild($layer); | this.layersContainer.appendChild($layer); | ||
| Linha 237: | Linha 235: | ||
$marker.setAttribute('data-marker-id', marker.id); | $marker.setAttribute('data-marker-id', marker.id); | ||
$marker.setAttribute('data-floor', floorId); | $marker.setAttribute('data-floor', floorId); | ||
$marker.style.position = 'absolute'; | $marker.style.position = 'absolute'; | ||
$marker.style.left = `${marker.x * this.currentZoom}px`; | $marker.style.left = `${marker.x * this.currentZoom}px`; | ||
| Linha 245: | Linha 241: | ||
$marker.style.transform = 'translate(-50%, -50%)'; | $marker.style.transform = 'translate(-50%, -50%)'; | ||
$marker.style.pointerEvents = 'auto'; | $marker.style.pointerEvents = 'auto'; | ||
const hasAction = marker.action && marker.action !== 'none'; | const hasAction = marker.action && marker.action !== 'none'; | ||
$marker.style.cursor = hasAction ? 'pointer' : 'default'; | $marker.style.cursor = hasAction ? 'pointer' : 'default'; | ||
const iconSize = Math.max(16, Math.floor(16 * this.currentZoom)); | const iconSize = Math.max(16, Math.floor(16 * this.currentZoom)); | ||
let iconHtml = ''; | let iconHtml = ''; | ||
if (marker.iconUrl && marker.iconUrl !== '') { | if (marker.iconUrl && marker.iconUrl !== '') { | ||
iconHtml = `<img src="${marker.iconUrl}" style="width:${iconSize}px; height:${iconSize}px; object-fit:contain;">`; | iconHtml = `<img src="${marker.iconUrl}" style="width:${iconSize}px; height:${iconSize}px; object-fit:contain;">`; | ||
| Linha 254: | Linha 253: | ||
iconHtml = `<i class="fas fa-map-marker-alt" style="font-size:${iconSize}px;"></i>`; | iconHtml = `<i class="fas fa-map-marker-alt" style="font-size:${iconSize}px;"></i>`; | ||
} | } | ||
$marker.innerHTML = ` | $marker.innerHTML = ` | ||
<div class="mapa-marker-icon" style="display:flex; align-items:center; justify-content:center; pointer-events:none;">${iconHtml}</div> | <div class="mapa-marker-icon" style="display:flex; align-items:center; justify-content:center; pointer-events:none;">${iconHtml}</div> | ||
<div class="mapa-marker-tooltip" 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 class="mapa-marker-tooltip" 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;"> | ||
<strong>${marker.name || 'Marcador'}</strong | <strong>${marker.name || 'Marcador'}</strong> | ||
</div> | </div> | ||
`; | `; | ||
$marker.addEventListener('mouseenter', () => { | $marker.addEventListener('mouseenter', () => { | ||
$marker.style.transform = 'translate(-50%, -50%) scale(1.1)'; | $marker.style.transform = 'translate(-50%, -50%) scale(1.1)'; | ||
| Linha 270: | Linha 269: | ||
} | } | ||
}); | }); | ||
$marker.addEventListener('mouseleave', () => { | $marker.addEventListener('mouseleave', () => { | ||
$marker.style.transform = 'translate(-50%, -50%) scale(1)'; | $marker.style.transform = 'translate(-50%, -50%) scale(1)'; | ||
| Linha 278: | Linha 278: | ||
} | } | ||
}); | }); | ||
if (hasAction) { | if (hasAction) { | ||
$marker.addEventListener('click', (e) => { | $marker.addEventListener('click', (e) => { | ||
| Linha 284: | Linha 285: | ||
}); | }); | ||
} | } | ||
return $marker; | return $marker; | ||
} | } | ||
| Linha 343: | Linha 333: | ||
}); | }); | ||
} | } | ||
const content = modal.querySelector('#mapa-viewer-popup-content'); | const content = modal.querySelector('#mapa-viewer-popup-content'); | ||
content.innerHTML = ` | content.innerHTML = ` | ||
<div style="display:flex; align-items:center; margin-bottom:12px;"> | <div style="display:flex; align-items:center; margin-bottom:12px;"> | ||
<h3 style="margin:0; color:#a5b4fc;">${marker.name}</h3> | <h3 style="margin:0; color:#a5b4fc;">${marker.name}</h3> | ||
</div> | </div> | ||
| Linha 365: | Linha 351: | ||
element.style.left = `${zoomedX}px`; | element.style.left = `${zoomedX}px`; | ||
element.style.top = `${zoomedY}px`; | element.style.top = `${zoomedY}px`; | ||
const iconSize = Math.max(24, Math.floor(24 * this.currentZoom)); | const iconSize = Math.max(24, Math.floor(24 * this.currentZoom)); | ||
const iconDiv = element.querySelector('.mapa-marker-icon'); | const iconDiv = element.querySelector('.mapa-marker-icon'); | ||
| Linha 373: | Linha 360: | ||
img.style.width = `${iconSize}px`; | img.style.width = `${iconSize}px`; | ||
img.style.height = `${iconSize}px`; | img.style.height = `${iconSize}px`; | ||
} | } | ||
} else { | } else { | ||
| Linha 380: | Linha 365: | ||
if (icon) { | if (icon) { | ||
icon.style.fontSize = `${iconSize}px`; | icon.style.fontSize = `${iconSize}px`; | ||
} | } | ||
} | } | ||
| Linha 424: | Linha 407: | ||
const scrollX = (this.viewport.scrollLeft + centerX) / oldZoom; | const scrollX = (this.viewport.scrollLeft + centerX) / oldZoom; | ||
const scrollY = (this.viewport.scrollTop + centerY) / oldZoom; | const scrollY = (this.viewport.scrollTop + centerY) / oldZoom; | ||
document.querySelectorAll('.mapa-image').forEach(img => { | document.querySelectorAll('.mapa-image').forEach(img => { | ||
img.style.transform = `scale(${this.currentZoom})`; | img.style.transform = `scale(${this.currentZoom})`; | ||
}); | }); | ||
this.updateMarkersPosition(); | this.updateMarkersPosition(); | ||
this.viewport.scrollLeft = scrollX * this.currentZoom - centerX; | this.viewport.scrollLeft = scrollX * this.currentZoom - centerX; | ||
| Linha 442: | Linha 427: | ||
prevFloor() { | prevFloor() { | ||
const | const layers = this.config.layers.sort((a,b) => a.id - b.id); | ||
if ( | const currentIndex = layers.findIndex(l => l.id === this.currentFloor); | ||
this.goToFloor( | if (currentIndex > 0) { | ||
this.goToFloor(layers[currentIndex - 1].id); | |||
} | } | ||
} | } | ||
nextFloor() { | nextFloor() { | ||
const | const layers = this.config.layers.sort((a,b) => a.id - b.id); | ||
if ( | const currentIndex = layers.findIndex(l => l.id === this.currentFloor); | ||
this.goToFloor( | if (currentIndex < layers.length - 1) { | ||
this.goToFloor(layers[currentIndex + 1].id); | |||
} | } | ||
} | } | ||
| Linha 481: | Linha 468: | ||
} | } | ||
} | } | ||
const viewportWidth = this.viewport.clientWidth; | const viewportWidth = this.viewport.clientWidth; | ||
const viewportHeight = this.viewport.clientHeight; | const viewportHeight = this.viewport.clientHeight; | ||
let screenX = | let screenX = x * this.currentZoom; | ||
let screenY = | let screenY = y * this.currentZoom; | ||
let targetScrollX = screenX - (viewportWidth / 2); | let targetScrollX = screenX - (viewportWidth / 2); | ||
let targetScrollY = screenY - (viewportHeight / 2); | let targetScrollY = screenY - (viewportHeight / 2); | ||
this.viewport.scrollLeft = Math.max(0, targetScrollX); | this.viewport.scrollLeft = Math.max(0, targetScrollX); | ||
this.viewport.scrollTop = Math.max(0, targetScrollY); | this.viewport.scrollTop = Math.max(0, targetScrollY); | ||
} | } | ||
| Linha 544: | Linha 511: | ||
} | } | ||
// Adicionar CSS da animação | |||
const style = document.createElement('style'); | const style = document.createElement('style'); | ||
style.textContent = ` | style.textContent = ` | ||
| Linha 555: | Linha 523: | ||
window.MapaViewer = MapaViewer; | window.MapaViewer = MapaViewer; | ||
const containerId = 'mapa-viewer-{ | // Inicializar | ||
const containerId = 'mapa-viewer-<!--{$id|escape:'quotes'|default:'mapa-default'}-->'; | |||
function initMapaViewer() { | function initMapaViewer() { | ||
const container = document.getElementById(containerId); | const container = document.getElementById(containerId); | ||
if (container && !container.hasAttribute('data-initialized')) { | if (container && !container.hasAttribute('data-initialized')) { | ||
container.setAttribute('data-initialized', 'true'); | container.setAttribute('data-initialized', 'true'); | ||
<!--{$configuracao}--> | |||
} | } | ||
} | } | ||