mesa-react / frontend /src /components /MapFrame.jsx
Guilherme Silberfarb Costa
update a lot of things
e8db196
raw
history blame
2.79 kB
import React, { useCallback, useEffect, useMemo, useRef } from 'react'
function hashHtml(value) {
let hash = 0
const step = Math.max(1, Math.floor(value.length / 64))
for (let i = 0; i < value.length; i += step) {
hash = ((hash << 5) - hash) + value.charCodeAt(i)
hash |= 0
}
return `${value.length}-${Math.abs(hash)}`
}
export default function MapFrame({ html }) {
const iframeRef = useRef(null)
const timersRef = useRef([])
const frameKey = useMemo(() => hashHtml(html || ''), [html])
const clearTimers = useCallback(() => {
timersRef.current.forEach((id) => window.clearTimeout(id))
timersRef.current = []
}, [])
const recenterFromLayers = useCallback(() => {
const iframe = iframeRef.current
if (!iframe) return
try {
const win = iframe.contentWindow
const doc = iframe.contentDocument || win?.document
if (!win || !doc || !win.L) return
const maps = Object.values(win).filter(
(item) => item
&& typeof item.fitBounds === 'function'
&& typeof item.eachLayer === 'function'
&& typeof item.invalidateSize === 'function',
)
const map = maps[0]
if (!map) return
map.invalidateSize(true)
const bounds = win.L.latLngBounds([])
map.eachLayer((layer) => {
try {
if (typeof layer.getLatLng === 'function') {
const latlng = layer.getLatLng()
if (latlng && Number.isFinite(latlng.lat) && Number.isFinite(latlng.lng)) {
bounds.extend(latlng)
}
return
}
if (typeof layer.getBounds === 'function') {
const layerBounds = layer.getBounds()
if (layerBounds && typeof layerBounds.isValid === 'function' && layerBounds.isValid()) {
bounds.extend(layerBounds)
}
}
} catch {
// no-op
}
})
if (bounds.isValid()) {
map.fitBounds(bounds, { padding: [20, 20], maxZoom: 17, animate: false })
}
} catch {
// no-op
}
}, [])
const scheduleRecenter = useCallback(() => {
clearTimers()
;[40, 180, 520, 1100].forEach((delay) => {
const timerId = window.setTimeout(() => {
recenterFromLayers()
}, delay)
timersRef.current.push(timerId)
})
}, [clearTimers, recenterFromLayers])
useEffect(() => {
return () => {
clearTimers()
}
}, [clearTimers])
if (!html) {
return <div className="empty-box">Mapa indisponivel.</div>
}
return (
<iframe
key={frameKey}
ref={iframeRef}
title="mapa"
className="map-frame"
srcDoc={html}
sandbox="allow-scripts allow-same-origin allow-popups"
onLoad={scheduleRecenter}
/>
)
}