Download templates/map.backup.html from Sebastiankay/eft_group_map_websocket: direct link, hf CLI and curl.
- Browser
- Download file 26.9 kB
-
https://huggingface.co/spaces/Sebastiankay/eft_group_map_websocket/resolve/main/templates/map.backup.html
- Command line
-
hf download hf://spaces/Sebastiankay/eft_group_map_websocket/templates/map.backup.html
-
curl -L -o map.backup.html https://huggingface.co/spaces/Sebastiankay/eft_group_map_websocket/resolve/main/templates/map.backup.html
26.9 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>{{ maps[0].name }} | Map with friends</title> | |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico" /> | |
| <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" /> | |
| <!--link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet-groupedlayercontrol/0.6.1/leaflet.groupedlayercontrol.css"/--> | |
| <script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script> | |
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.2/css/bulma.min.css" /> | |
| <link rel="stylesheet" href="/static/style.css" /> | |
| <style> | |
| html, | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| } | |
| #map { | |
| width: 100%; | |
| height: 100vh; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="map"></div> | |
| <script src="/static/js/leaflet.controlGroupedlayer.js"></script> | |
| <script src="/static/js/leaflet.controlCoordinates.js"></script> | |
| <script> | |
| const mapData = {{ maps[0] | tojson }} | |
| //const transform = [0.1855, 113.1, 0.1855, 167.8] | |
| const transform = mapData.transform | |
| const bounds = mapData.bounds | |
| const svgBounds = mapData.svgBounds ? mapData.svgBounds : bounds | |
| const coordinateRotation = mapData.coordinateRotation ? mapData.coordinateRotation : 0 | |
| const svgPath = mapData.svgPath | |
| const imageUrl = mapData.svgPath | |
| const minZoom = mapData.minZoom ? mapData.minZoom : 1 | |
| const maxZoom = mapData.maxZoom ? mapData.maxZoom : 6 | |
| const showElevation = false; | |
| const ws = new WebSocket("ws://localhost:8000/"); | |
| ws.onmessage = function (event) { | |
| console.log(event.data); | |
| const data = JSON.parse(event.data); | |
| if (data.type === "coordinates") { | |
| addMarker(data.x, data.y, data.z); | |
| } | |
| }; | |
| const images = { | |
| 'container_bank-cash-register': 'container_cash-register', | |
| 'container_bank-safe': 'container_safe', | |
| 'container_buried-barrel-cache': 'container_buried-barrel-cache', | |
| 'container_cash-register': 'container_cash-register', | |
| 'container_cash-register-tar2-2': 'container_cash-register', | |
| 'container_dead-civilian': 'container_dead-scav', | |
| 'container_dead-scav': 'container_dead-scav', | |
| 'container_festive-airdrop-supply-crate': 'container_festive-airdrop-supply-crate', | |
| 'container_pmc-body': 'container_dead-scav', | |
| 'container_civilian-body': 'container_dead-scav', | |
| 'container_drawer': 'container_drawer', | |
| 'container_duffle-bag': 'container_duffle-bag', | |
| 'container_grenade-box': 'container_grenade-box', | |
| 'container_ground-cache': 'container_ground-cache', | |
| 'container_jacket': 'container_jacket', | |
| 'container_lab-technician-body': 'container_dead-scav', | |
| 'container_medbag-smu06': 'container_medbag-smu06', | |
| 'container_medcase': 'container_medcase', | |
| 'container_medical-supply-crate': 'container_crate', | |
| 'container_pc-block': 'container_pc-block', | |
| 'container_plastic-suitcase': 'container_plastic-suitcase', | |
| 'container_ration-supply-crate': 'container_crate', | |
| 'container_safe': 'container_safe', | |
| 'container_scav-body': 'container_dead-scav', | |
| 'container_shturmans-stash': 'container_weapon-box', | |
| 'container_technical-supply-crate': 'container_crate', | |
| 'container_toolbox': 'container_toolbox', | |
| 'container_weapon-box': 'container_weapon-box', | |
| 'container_wooden-ammo-box': 'container_wooden-ammo-box', | |
| 'container_wooden-crate': 'container_wooden-crate', | |
| 'extract_pmc': 'extract_pmc', | |
| 'extract_scav': 'extract_scav', | |
| 'extract_shared': 'extract_shared', | |
| 'extract_transit': 'extract_transit', | |
| 'hazard': 'hazard', | |
| 'hazard_mortar': 'hazard_mortar', | |
| 'hazard_minefield': 'hazard', | |
| 'hazard_sniper': 'hazard', | |
| 'key': 'key', | |
| 'lock': 'lock', | |
| 'loose_loot': 'loose_loot', | |
| 'quest_item': 'quest_item', | |
| 'quest_objective': 'quest_objective', | |
| 'spawn_sniper_scav': 'spawn_sniper_scav', | |
| 'spawn_bloodhound': 'spawn_bloodhound', | |
| 'spawn_boss': 'spawn_boss', | |
| 'spawn_cultist-priest': 'spawn_cultist-priest', | |
| 'spawn_pmc': 'spawn_pmc', | |
| 'spawn_rogue': 'spawn_rogue', | |
| 'spawn_scav': 'spawn_scav', | |
| 'stationarygun': 'stationarygun', | |
| 'switch': 'switch', | |
| }; | |
| const categories = { | |
| 'extract_pmc': 'PMC', | |
| 'extract_shared': 'Shared', | |
| 'extract_scav': 'Scav', | |
| 'extract_transit': 'Transit', | |
| 'spawn_sniper_scav': 'Sniper Scav', | |
| 'spawn_pmc': 'PMC', | |
| 'spawn_scav': 'Scav', | |
| 'spawn_boss': 'Boss', | |
| 'quest_item': 'Item', | |
| 'quest_objective': 'Objective', | |
| 'lock': 'Locks', | |
| 'lever': 'Lever', | |
| 'stationarygun': 'Stationary Gun', | |
| 'switch': 'Switch', | |
| 'place-names': 'Place Names', | |
| }; | |
| function getCRS(transform) { | |
| let scaleX = 1; | |
| let scaleY = 1; | |
| let marginX = 0; | |
| let marginY = 0; | |
| if (transform) { | |
| scaleX = transform[0]; | |
| scaleY = transform[2] * -1; | |
| marginX = transform[1]; | |
| marginY = transform[3]; | |
| } | |
| return L.extend({}, L.CRS.Simple, { | |
| transformation: new L.Transformation(scaleX, marginX, scaleY, marginY), | |
| projection: L.extend({}, L.Projection.LonLat, { | |
| project: latLng => { | |
| return L.Projection.LonLat.project(applyRotation(latLng, coordinateRotation)); | |
| }, | |
| unproject: point => { | |
| return applyRotation(L.Projection.LonLat.unproject(point), coordinateRotation * -1); | |
| }, | |
| }), | |
| }); | |
| } | |
| function applyRotation(latLng, rotation) { | |
| if (!latLng.lng && !latLng.lat) { | |
| return L.latLng(0, 0); | |
| } | |
| if (!rotation) { | |
| return latLng; | |
| } | |
| const angleInRadians = (rotation * Math.PI) / 180; | |
| const cosAngle = Math.cos(angleInRadians); | |
| const sinAngle = Math.sin(angleInRadians); | |
| const { lng: x, lat: y } = latLng; | |
| const rotatedX = x * cosAngle - y * sinAngle; | |
| const rotatedY = x * sinAngle + y * cosAngle; | |
| return L.latLng(rotatedY, rotatedX); | |
| } | |
| function pos(position) { | |
| return [position.z, position.x]; | |
| } | |
| function addElevation(item, popup) { | |
| if (!showElevation) { | |
| return; | |
| } | |
| const elevationContent = L.DomUtil.create('div', undefined, popup); | |
| elevationContent.textContent = `Elevation: ${item.position.y.toFixed(2)}`; | |
| if (item.top && item.bottom && item.top !== item.position.y && item.bottom !== item.position.y) { | |
| const heightContent = L.DomUtil.create('div', undefined, popup); | |
| heightContent.textContent = `Top ${item.top.toFixed(2)}, bottom: ${item.bottom.toFixed(2)}`; | |
| } | |
| } | |
| function markerIsOnLayer(marker, layer) { | |
| if (!layer) { | |
| return true; | |
| } | |
| var top = marker.options.top || marker.options.position.y; | |
| var bottom = marker.options.bottom || marker.options.position.y; | |
| for (const extent of layer.options.extents) { | |
| if (top >= extent.height[0] && bottom < extent.height[1]) { | |
| let containedType = 'partial'; | |
| if (bottom >= extent.height[0] && top <= extent.height[1]) { | |
| containedType = 'full'; | |
| } | |
| if (extent.bounds) { | |
| for (const boundsArray of extent.bounds) { | |
| const bounds = getBounds(boundsArray); | |
| if (bounds.contains(pos(marker.options.position))) { | |
| return containedType; | |
| } | |
| } | |
| } else { | |
| return containedType; | |
| } | |
| } | |
| } | |
| return false; | |
| } | |
| function markerIsOnActiveLayer(marker) { | |
| if (!marker.options.position) { | |
| return true; | |
| } | |
| const map = marker._map; | |
| // check if marker is completely contained by inactive layer | |
| const overlays = map.layerControl._layers.map(l => l.layer).filter(l => Boolean(l.options.extents) && l.options.overlay); | |
| for (const layer of overlays) { | |
| for (const extent of layer.options.extents) { | |
| if (markerIsOnLayer(marker, layer) === 'full' && !map.hasLayer(layer) && extent.bounds) { | |
| return false; | |
| } | |
| } | |
| } | |
| // check if marker is on active overlay | |
| const activeOverlay = Object.values(map._layers).find(l => l.options?.extents && l.options?.overlay); | |
| if (activeOverlay && markerIsOnLayer(marker, activeOverlay)) { | |
| return true; | |
| } | |
| // check if marker is on base layer | |
| const baseLayer = Object.values(map._layers).find(l => l.options?.extents && !L.options?.overlay); | |
| if (!activeOverlay && markerIsOnLayer(marker, baseLayer)) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| function checkMarkerForActiveLayers(event) { | |
| const marker = event.target || event; | |
| const outline = marker.options.outline; | |
| const onLevel = markerIsOnActiveLayer(marker); | |
| if (onLevel) { | |
| marker._icon?.classList.remove('off-level'); | |
| if (outline) { | |
| outline._path?.classList.remove('off-level'); | |
| } | |
| } else { | |
| marker._icon?.classList.add('off-level'); | |
| if (outline) { | |
| outline._path?.classList.add('off-level'); | |
| } | |
| } | |
| } | |
| function activateMarkerLayer(event) { | |
| const marker = event.target || event; | |
| if (markerIsOnActiveLayer(marker)) { | |
| return; | |
| } | |
| const activeLayers = Object.values(marker._map._layers).filter(l => l.options?.extents && l.options?.overlay); | |
| for (const layer of activeLayers) { | |
| layer.removeFrom(marker._map); | |
| } | |
| const heightLayers = marker._map.layerControl._layers.filter(l => l.layer.options.extents && l.layer.options.overlay).map(l => l.layer); | |
| for (const layer of heightLayers) { | |
| if (markerIsOnLayer(marker, layer)) { | |
| layer.addTo(marker._map); | |
| break; | |
| } | |
| } | |
| } | |
| const getALink = (path, contents) => { | |
| const a = L.DomUtil.create('a'); | |
| a.setAttribute('href', path); | |
| a.setAttribute('target', '_blank'); | |
| a.append(contents); | |
| // a.addEventListener('click', (event) => { | |
| // navigate(path); | |
| // event.preventDefault(); | |
| // }); | |
| return a; | |
| }; | |
| function getScaledBounds(bounds, scaleFactor) { | |
| // Calculate the center point of the bounds | |
| const centerX = (bounds[0][0] + bounds[1][0]) / 2; | |
| const centerY = (bounds[0][1] + bounds[1][1]) / 2; | |
| // Calculate the new width and height | |
| const width = bounds[1][0] - bounds[0][0]; | |
| const height = bounds[1][1] - bounds[0][1]; | |
| const newWidth = width * scaleFactor; | |
| const newHeight = height * scaleFactor; | |
| // Update the coordinates of the two points defining the bounds | |
| const newBounds = [ | |
| [centerY - newHeight / 2, centerX - newWidth / 2], | |
| [centerY + newHeight / 2, centerX + newWidth / 2] | |
| ]; | |
| // console.log("Initial Rectangle:", bounds); | |
| // console.log("Scaled Rectangle:", newBounds); | |
| // console.log("Center:", L.bounds(bounds).getCenter(true)); | |
| return newBounds; | |
| } | |
| // Erstelle die Karte | |
| //const map = L.map('map').setView([0, 0], 2); | |
| const map = L.map('map', { | |
| maxBounds: getScaledBounds(svgBounds, 1.5), | |
| //maxBounds: bounds, | |
| center: [0, 0], | |
| zoom: 2, | |
| minZoom: minZoom, | |
| maxZoom: maxZoom, | |
| zoomSnap: 0.1, | |
| scrollWheelZoom: true, | |
| wheelPxPerZoomLevel: 120, | |
| crs: getCRS(transform), | |
| attributionControl: false, | |
| id: "wwoodsMap", | |
| }); | |
| const layerControl = L.control.groupedLayers(null, null, { | |
| position: 'topleft', | |
| collapsed: true, | |
| groupCheckboxes: true, | |
| groupsCollapsable: true, | |
| exclusiveOptionalGroups: ['Levels'], | |
| }).addTo(map); | |
| layerControl.on('overlayToggle', (e) => { | |
| const layerState = e.detail; | |
| if (layerState.checked) { | |
| mapViewRef.current.layer = layerState.key; | |
| } else { | |
| mapViewRef.current.layer = undefined; | |
| } | |
| }); | |
| layerControl.on('layerToggle', (e) => { | |
| const layerState = e.detail; | |
| if (!layerState.checked) { | |
| mapSettingsRef.current.hiddenLayers.push(layerState.key); | |
| } else { | |
| mapViewRef.current.layer = layerState.key; | |
| mapSettingsRef.current.hiddenLayers = mapSettingsRef.current.hiddenLayers.filter(key => key !== layerState.key); | |
| } | |
| updateSavedMapSettings(); | |
| }); | |
| layerControl.on('groupToggle', (e) => { | |
| const groupState = e.detail; | |
| for (const groupLayer of layerControl._layers) { | |
| if (groupLayer.group?.key !== groupState.key) { | |
| continue; | |
| } | |
| if (!groupState.checked) { | |
| mapSettingsRef.current.hiddenLayers.push(groupLayer.key); | |
| } else { | |
| mapSettingsRef.current.hiddenLayers = mapSettingsRef.current.hiddenLayers.filter(key => key !== groupLayer.key); | |
| } | |
| } | |
| if (!groupState.checked) { | |
| mapSettingsRef.current.hiddenGroups.push(groupState.key); | |
| } else { | |
| mapSettingsRef.current.hiddenGroups = mapSettingsRef.current.hiddenGroups.filter(key => key !== groupState.key); | |
| } | |
| updateSavedMapSettings(); | |
| }); | |
| layerControl.on('groupCollapseToggle', (e) => { | |
| const groupState = e.detail; | |
| if (groupState.collapsed) { | |
| mapSettingsRef.current.collapsedGroups.push(groupState.key); | |
| } else { | |
| mapSettingsRef.current.collapsedGroups = mapSettingsRef.current.collapsedGroups.filter(key => key !== groupState.key); | |
| } | |
| updateSavedMapSettings(); | |
| }); | |
| const getLayerOptions = (layerKey, groupKey, layerName) => { | |
| return { | |
| groupKey, | |
| layerKey, | |
| groupName: groupKey, | |
| layerName: layerName || categories[layerKey] || layerKey, | |
| //groupHidden: Boolean(mapSettingsRef.current.hiddenGroups?.includes(groupKey)), | |
| //layerHidden: Boolean(mapSettingsRef.current.hiddenLayers?.includes(layerKey)), | |
| image: images[layerKey] ? "/static/maps/interactive/${images[layerKey]}.png" : undefined, | |
| //groupCollapsed: Boolean(mapSettingsRef.current.collapsedGroups?.includes(groupKey)), | |
| }; | |
| }; | |
| const addLayer = (layer, layerKey, groupKey, layerName) => { | |
| layer.key = layerKey; | |
| const layerOptions = getLayerOptions(layerKey, groupKey, layerName); | |
| if (!layerOptions.layerHidden) { | |
| layer.addTo(map); | |
| } | |
| layerControl.addOverlay(layer, layerOptions.layerName, layerOptions); | |
| }; | |
| map.layerControl = layerControl; | |
| // Hinzufügen des Image-Overlays | |
| const overlay = L.imageOverlay(imageUrl, getBounds(svgBounds)); | |
| overlay.addTo(map); | |
| function checkMarkerBounds(position, markerBounds) { | |
| if (position.x < markerBounds.TL.x) markerBounds.TL.x = position.x; | |
| if (position.z > markerBounds.TL.z) markerBounds.TL.z = position.z; | |
| if (position.x > markerBounds.BR.x) markerBounds.BR.x = position.x; | |
| if (position.z < markerBounds.BR.z) markerBounds.BR.z = position.z; | |
| } | |
| function getBounds(bounds) { | |
| if (!bounds) { | |
| return undefined; | |
| } | |
| return L.latLngBounds([bounds[0][1], bounds[0][0]], [bounds[1][1], bounds[1][0]]); | |
| //return [[bounds[0][1], bounds[0][0]], [bounds[1][1], bounds[1][0]]]; | |
| } | |
| const layerOptions = { | |
| maxZoom: maxZoom, | |
| maxNativeZoom: maxZoom, | |
| extents: [ | |
| { | |
| height: [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER], | |
| bounds: [bounds], | |
| } | |
| ], | |
| type: 'map-layer', | |
| }; | |
| let tileLayer = false; | |
| const baseLayers = []; | |
| const tileSize = 256; | |
| let svgLayer = false; | |
| if (svgPath) { | |
| const svgBounds2 = svgBounds ? getBounds(svgBounds) : bounds; | |
| svgLayer = L.imageOverlay(svgPath, svgBounds2, layerOptions); | |
| baseLayers.push(svgLayer); | |
| } | |
| const positionIsInBounds = (position) => { | |
| return getBounds(bounds).contains(pos(position)); | |
| }; | |
| let markerBounds = { | |
| 'TL': { x: Number.MAX_SAFE_INTEGER, z: Number.MIN_SAFE_INTEGER }, | |
| 'BR': { x: Number.MIN_SAFE_INTEGER, z: Number.MAX_SAFE_INTEGER } | |
| } | |
| if (mapData.labels?.length > 0) { | |
| const labelsGroup = L.layerGroup(); | |
| const defaultHeight = ((layerOptions.extents[0].height[1] - layerOptions.extents[0].height[0]) / 2) + layerOptions.extents[0].height[0]; | |
| for (const label of mapData.labels) { | |
| const fontSize = label.size ? label.size : 100; | |
| const height = label.position.length < 3 ? defaultHeight : label.position[2]; | |
| const rotation = label.rotation ? label.rotation : 0; | |
| L.marker(pos({ x: label.position[0], z: label.position[1] }), { | |
| icon: L.divIcon({ html: `<div class="label" style="font-size: ${fontSize}%; transform: translate3d(-50%, -50%, 0) rotate(${rotation}deg)">${label.text}</div>`, className: 'map-area-label', layers: baseLayers, }), | |
| interactive: false, | |
| zIndexOffset: -100000, | |
| position: { | |
| x: label.position[0], | |
| y: height, | |
| z: label.position[1], | |
| }, | |
| top: typeof label.top !== 'undefined' ? label.top : 1000, | |
| bottom: typeof label.bottom !== 'undefined' ? label.bottom : -1000, | |
| }).addTo(labelsGroup); | |
| } | |
| addLayer(labelsGroup, 'place-names', 'Landmarks'); | |
| //labelsGroup.addTo(map); | |
| } | |
| // Add spawns | |
| if (mapData.spawns.length > 0) { | |
| const spawnLayers = { | |
| 'pmc': L.layerGroup(), | |
| 'scav': L.layerGroup(), | |
| 'sniper_scav': L.layerGroup(), | |
| 'boss': L.layerGroup(), | |
| 'cultist-priest': L.layerGroup(), | |
| 'rogue': L.layerGroup(), | |
| 'bloodhound': L.layerGroup(), | |
| } | |
| for (const spawn of mapData.spawns) { | |
| if (!positionIsInBounds(spawn.position)) { | |
| continue; | |
| } | |
| let spawnType = ''; | |
| let bosses = []; | |
| if (spawn.categories.includes('boss')) { | |
| bosses = mapData.bosses.filter(boss => boss.spawnLocations.some(sl => sl.spawnKey === spawn.zoneName)); | |
| if (bosses.length === 0) { | |
| if (spawn.categories.includes('bot') && spawn.sides.includes('scav')) { | |
| spawnType = 'scav'; | |
| } | |
| else { | |
| console.error(`Unusual spawn: ${spawn.sides}, ${spawn.categories}`); | |
| continue; | |
| } | |
| } | |
| else if (bosses.length === 1 && (bosses[0].normalizedName === 'bloodhound' || bosses[0].normalizedName === 'cultist-priest' || bosses[0].normalizedName === 'rogue')) { | |
| spawnType = bosses[0].normalizedName; | |
| } | |
| else { | |
| spawnType = 'boss'; | |
| } | |
| } else if (spawn.categories.includes('sniper')) { | |
| spawnType = 'sniper_scav'; | |
| } else if (spawn.sides.includes('scav')) { | |
| if (spawn.categories.includes('bot') || spawn.categories.includes('all')) { | |
| spawnType = 'scav'; | |
| } | |
| else { | |
| console.error(`Unusual spawn: ${spawn.sides}, ${spawn.categories}`); | |
| continue; | |
| } | |
| } | |
| else if (spawn.categories.includes('player')) { | |
| if (spawn.sides.includes('pmc') || spawn.sides.includes('all')) { | |
| spawnType = 'pmc' | |
| } | |
| else { | |
| console.error(`Unusual spawn: ${spawn.sides}, ${spawn.categories}`); | |
| continue; | |
| } | |
| } | |
| else { | |
| console.error(`Unusual spawn: ${spawn.sides}, ${spawn.categories}`); | |
| continue; | |
| } | |
| const spawnIcon = L.icon({ | |
| iconUrl: `/static/maps/interactive/spawn_${spawnType}.png`, | |
| iconSize: [24, 24], | |
| popupAnchor: [0, -12], | |
| }); | |
| if (spawnType === 'pmc') { | |
| spawnIcon.iconAnchor = [12, 24]; | |
| spawnIcon.popupAnchor = [0, -24]; | |
| } | |
| const popupContent = L.DomUtil.create('div'); | |
| if (spawn.categories.includes('boss') && bosses.length > 0) { | |
| bosses = bosses.reduce((unique, current) => { | |
| if (!unique.some(b => b.normalizedName === current.normalizedName)) { | |
| unique.push(current); | |
| if (!categories[`spawn_${current.normalizedName}`]) { | |
| categories[`spawn_${current.normalizedName}`] = current.name; | |
| } | |
| } | |
| return unique; | |
| }, []); | |
| const bossList = L.DomUtil.create('div', undefined, popupContent); | |
| for (const boss of bosses) { | |
| if (bossList.childNodes.length > 0) { | |
| const comma = L.DomUtil.create('span', undefined, bossList); | |
| comma.textContent = ', '; | |
| } | |
| bossList.append(getALink(`https://escapefromtarkov.fandom.com/wiki/Special:Search?scope=internal&query=${boss.name}`, `${boss.name} (${Math.round(boss.spawnChance * 100)}%)`)); | |
| } | |
| } | |
| else { | |
| const spawnDiv = L.DomUtil.create('div', undefined, popupContent); | |
| spawnDiv.textContent = categories[`spawn_${spawnType}`]; | |
| } | |
| addElevation(spawn, popupContent); | |
| const marker = L.marker(pos(spawn.position), { | |
| icon: spawnIcon, | |
| position: spawn.position, | |
| }); | |
| if (popupContent.childNodes.length > 0) { | |
| marker.bindPopup(L.popup().setContent(popupContent)); | |
| } | |
| marker.position = spawn.position; | |
| marker.on('add', checkMarkerForActiveLayers); | |
| marker.on('click', activateMarkerLayer); | |
| marker.addTo(spawnLayers[spawnType]); | |
| checkMarkerBounds(spawn.position, markerBounds); | |
| } | |
| for (const key in spawnLayers) { | |
| if (Object.keys(spawnLayers[key]._layers).length > 0) { | |
| addLayer(spawnLayers[key], `spawn_${key}`, 'Spawns'); | |
| } | |
| } | |
| } | |
| // Function to add a marker at the given coordinates | |
| function addMarker(x, y, z) { | |
| const position = { x: x, y: y, z: z }; | |
| const markerIcon = L.icon({ | |
| iconUrl: '/static/maps/interactive/marker.png', | |
| iconSize: [24, 24], | |
| popupAnchor: [0, -12], | |
| }); | |
| const marker = L.marker(pos(position), { | |
| icon: markerIcon, | |
| position: position, | |
| }); | |
| marker.addTo(map); | |
| } | |
| </script> | |
| </body> | |
| </html> |