Enhance map functionality and API documentation

- Updated API documentation for the `rebuildZooms` endpoint to clarify its long execution time and response behavior.
- Modified MapView component to manage tile cache invalidation after rebuilding zoom levels, ensuring fresh tile display.
- Introduced a new composable for handling tile cache invalidation state after admin actions.
- Enhanced character icon creation to reflect ownership status with distinct colors.
- Improved loading state handling in various components for better user experience during data fetching.
This commit is contained in:
2026-03-01 19:09:46 +03:00
parent 8331473808
commit 225aaa36e7
16 changed files with 236 additions and 52 deletions

View File

@@ -195,6 +195,8 @@ let intervalId: ReturnType<typeof setInterval> | null = null
let autoMode = false
let mapContainer: HTMLElement | null = null
let contextMenuHandler: ((ev: MouseEvent) => void) | null = null
let mounted = false
let visibilityChangeHandler: (() => void) | null = null
function toLatLng(x: number, y: number) {
return leafletMap!.unproject([x, y], HnHMaxZoom)
@@ -264,6 +266,7 @@ function onKeydown(e: KeyboardEvent) {
}
onMounted(async () => {
mounted = true
if (import.meta.client) {
window.addEventListener('keydown', onKeydown)
}
@@ -353,9 +356,11 @@ onMounted(async () => {
getCurrentMapId: () => mapLogic.state.mapid.value,
connectionStateRef: sseConnectionState,
onMerge: (mapTo: number, shift: { x: number; y: number }) => {
if (!mounted) return
const latLng = toLatLng(shift.x * 100, shift.y * 100)
layersManager!.changeMap(mapTo)
api.getMarkers().then((body) => {
if (!mounted) return
layersManager!.updateMarkers(Array.isArray(body) ? body : [])
questGivers.value = layersManager!.getQuestGivers()
})
@@ -363,6 +368,17 @@ onMounted(async () => {
},
})
const { shouldInvalidateTileCache, clearRebuildDoneFlag } = useRebuildZoomsInvalidation()
if (shouldInvalidateTileCache()) {
mapInit.layer.cache = {}
mapInit.overlayLayer.cache = {}
clearRebuildDoneFlag()
nextTick(() => {
mapInit.layer.redraw()
mapInit.overlayLayer.redraw()
})
}
const charsList = Array.isArray(charactersData) ? charactersData : []
layersManager.updateCharacters(charsList)
players.value = layersManager.getPlayers()
@@ -395,6 +411,7 @@ onMounted(async () => {
// Markers load asynchronously after map is visible.
api.getMarkers().then((body) => {
if (!mounted) return
layersManager!.updateMarkers(Array.isArray(body) ? body : [])
questGivers.value = layersManager!.getQuestGivers()
})
@@ -406,6 +423,7 @@ onMounted(async () => {
api
.getCharacters()
.then((body) => {
if (!mounted) return
const list = Array.isArray(body) ? body : []
layersManager!.updateCharacters(list)
players.value = layersManager!.getPlayers()
@@ -429,17 +447,31 @@ onMounted(async () => {
startCharacterPoll()
if (import.meta.client) {
document.addEventListener('visibilitychange', () => {
visibilityChangeHandler = () => {
startCharacterPoll()
})
}
document.addEventListener('visibilitychange', visibilityChangeHandler)
}
watch(mapLogic.state.showGridCoordinates, (v) => {
if (mapInit?.coordLayer) {
;(mapInit.coordLayer.options as { visible?: boolean }).visible = v
mapInit.coordLayer.setOpacity(v ? 1 : 0)
mapInit.coordLayer.redraw?.()
if (v) mapInit.coordLayer.bringToFront?.()
if (!mapInit?.coordLayer || !leafletMap) return
const coordLayer = mapInit.coordLayer
const layerWithMap = coordLayer as L.GridLayer & { _map?: L.Map }
if (v) {
;(coordLayer.options as { visible?: boolean }).visible = true
if (!layerWithMap._map) {
coordLayer.addTo(leafletMap)
coordLayer.setZIndex(500)
coordLayer.setOpacity(1)
coordLayer.bringToFront?.()
}
leafletMap.invalidateSize()
nextTick(() => {
coordLayer.redraw?.()
})
} else {
coordLayer.setOpacity(0)
coordLayer.remove()
}
})
@@ -553,8 +585,12 @@ onMounted(async () => {
})
onBeforeUnmount(() => {
mounted = false
if (import.meta.client) {
window.removeEventListener('keydown', onKeydown)
if (visibilityChangeHandler) {
document.removeEventListener('visibilitychange', visibilityChangeHandler)
}
}
mapNavigate.setGoTo(null)
if (contextMenuHandler) {

View File

@@ -56,7 +56,12 @@
Display
</h3>
<label class="label cursor-pointer justify-start gap-2 py-0 hover:bg-base-200/50 rounded-lg px-2 -mx-2 touch-manipulation" :class="touchFriendly ? 'min-h-11' : ''">
<input v-model="showGridCoordinates" type="checkbox" class="checkbox checkbox-sm" />
<input
v-model="showGridCoordinates"
type="checkbox"
class="checkbox checkbox-sm"
data-testid="show-grid-coordinates"
/>
<span>Show grid coordinates</span>
</label>
<label class="label cursor-pointer justify-start gap-2 py-0 hover:bg-base-200/50 rounded-lg px-2 -mx-2 touch-manipulation" :class="touchFriendly ? 'min-h-11' : ''">