Files
hnh-map/frontend-nuxt/lib/Character.ts
Nikolay Tatarinov 7bdaa6bfcc Enhance API and frontend components for character management and map visibility
- Updated API documentation to include `ownedByMe` field in character responses, indicating if a character was last updated by the current user's tokens.
- Modified MapView component to track and display the live status based on user-owned characters.
- Enhanced map data handling to exclude hidden maps for non-admin users and improved character icon representation on the map.
- Refactored character data structures to support new properties and ensure accurate rendering in the frontend.
2026-03-01 17:21:15 +03:00

109 lines
3.2 KiB
TypeScript

import { HnHMaxZoom } from '~/lib/LeafletCustomTypes'
import * as L from 'leaflet'
/** SVG data URL for character marker icon (teal pin, bottom-center anchor). */
const CHARACTER_ICON_URL =
'data:image/svg+xml,' +
encodeURIComponent(
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 32" width="24" height="32">' +
'<path fill="#0d9488" stroke="#0f766e" stroke-width="1" d="M12 2a6 6 0 0 1 6 6c0 4-6 10-6 10s-6-6-6-10a6 6 0 0 1 6-6z"/>' +
'<circle cx="12" cy="8" r="2.5" fill="white"/>' +
'</svg>'
)
const CHARACTER_ICON = new L.Icon({
iconUrl: CHARACTER_ICON_URL,
iconSize: [24, 32],
iconAnchor: [12, 32],
popupAnchor: [0, -32],
})
export interface CharacterData {
name: string
position: { x: number; y: number }
type: string
id: number
map: number
}
export interface CharacterMapViewRef {
map: L.Map
mapid: number
markerLayer?: L.LayerGroup
}
export interface MapCharacter {
id: number
name: string
position: { x: number; y: number }
type: string
map: number
text: string
value: number
leafletMarker: L.Marker | null
remove: (mapview: CharacterMapViewRef) => void
add: (mapview: CharacterMapViewRef) => void
update: (mapview: CharacterMapViewRef, updated: CharacterData | MapCharacter) => void
setClickCallback: (callback: (e: L.LeafletMouseEvent) => void) => void
}
export function createCharacter(data: CharacterData): MapCharacter {
let leafletMarker: L.Marker | null = null
let onClick: ((e: L.LeafletMouseEvent) => void) | null = null
const character: MapCharacter = {
id: data.id,
name: data.name,
position: { ...data.position },
type: data.type,
map: data.map,
text: data.name,
value: data.id,
get leafletMarker() {
return leafletMarker
},
remove(mapview: CharacterMapViewRef): void {
if (leafletMarker) {
const layer = mapview.markerLayer ?? mapview.map
layer.removeLayer(leafletMarker)
leafletMarker = null
}
},
add(mapview: CharacterMapViewRef): void {
if (character.map === mapview.mapid) {
const position = mapview.map.unproject([character.position.x, character.position.y], HnHMaxZoom)
leafletMarker = L.marker(position, { icon: CHARACTER_ICON, title: character.name })
leafletMarker.on('click', (e: L.LeafletMouseEvent) => {
if (onClick) onClick(e)
})
const targetLayer = mapview.markerLayer ?? mapview.map
leafletMarker.addTo(targetLayer)
}
},
update(mapview: CharacterMapViewRef, updated: CharacterData | MapCharacter): void {
if (character.map !== updated.map) {
character.remove(mapview)
}
character.map = updated.map
character.position = { ...updated.position }
if (!leafletMarker && character.map === mapview.mapid) {
character.add(mapview)
}
if (leafletMarker) {
const position = mapview.map.unproject([updated.position.x, updated.position.y], HnHMaxZoom)
leafletMarker.setLatLng(position)
}
},
setClickCallback(callback: (e: L.LeafletMouseEvent) => void): void {
onClick = callback
},
}
return character
}