From eb0ac9ce83c22e48aa7bfe21fe2d424504cd0031 Mon Sep 17 00:00:00 2001 From: Lanius Trolling Date: Sat, 27 Jan 2024 10:34:46 -0500 Subject: [PATCH] Improve map-object link handling --- .idea/misc.xml | 1 + .../info/mechyrdia/mapviewer/entryPoint.kt | 4 +- .../kotlin/info/mechyrdia/mapviewer/render.kt | 128 ++++++++---------- .../kotlin/info/mechyrdia/mapviewer/utils.kt | 4 + 4 files changed, 66 insertions(+), 71 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 1ad7afe..585a745 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -92,6 +92,7 @@ + diff --git a/src/mapMain/kotlin/info/mechyrdia/mapviewer/entryPoint.kt b/src/mapMain/kotlin/info/mechyrdia/mapviewer/entryPoint.kt index a06770c..45dccd1 100644 --- a/src/mapMain/kotlin/info/mechyrdia/mapviewer/entryPoint.kt +++ b/src/mapMain/kotlin/info/mechyrdia/mapviewer/entryPoint.kt @@ -1,15 +1,15 @@ package info.mechyrdia.mapviewer import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch -import kotlinx.coroutines.supervisorScope lateinit var galaxyMap: GalaxyMap lateinit var galaxyLore: GalaxyLore suspend fun main() { - supervisorScope { + coroutineScope { val ptrProvider = initPopHistoryEntryHandler() val (map, lore) = showLoadingScreen { diff --git a/src/mapMain/kotlin/info/mechyrdia/mapviewer/render.kt b/src/mapMain/kotlin/info/mechyrdia/mapviewer/render.kt index 300bdcd..7eff1b5 100644 --- a/src/mapMain/kotlin/info/mechyrdia/mapviewer/render.kt +++ b/src/mapMain/kotlin/info/mechyrdia/mapviewer/render.kt @@ -26,9 +26,24 @@ private fun renderInNewTab(ptr: MapObjectPtr) { window.open(ptr.toUrl().href, "_blank") } +private var mapPan: MapPan? = null + private var hammerInstance: HammerManager? = null -private fun CoroutineScope.openPtr(target: MapObjectPtr, currentSectorId: String?) { +private fun SectorMapPan.moveCameraToSelection(sector: SectorMap, selection: SectorMapSelection) { + val (newX, newY) = when (selection) { + SectorMapSelection.NoSelection -> Vector2(0, 0) + is SectorMapSelection.SelectedSystem -> sector.starSystems.getValue(selection.system).location + is SectorMapSelection.SelectedBody -> { + val system = sector.starSystems.getValue(selection.system) + Vector2().copy(system.location).add(system.celestialBodies.getValue(selection.body).location) + } + } + + moveTo(newX, newY) +} + +private fun CoroutineScope.openPtr(target: MapObjectPtr, currentSectorId: String?, panToSelection: Boolean) { if (target.sector == currentSectorId) { val selection = when (target) { GalaxyPtr -> null @@ -41,6 +56,9 @@ private fun CoroutineScope.openPtr(target: MapObjectPtr, currentSectorId: String setSelectedLabel(selection) setCurrentLocation(target) + + if (panToSelection) + (mapPan as? SectorMapPan)?.moveCameraToSelection(galaxyMap.sectors.getValue(currentSectorId!!), selection!!) } else { if (target == GalaxyPtr && currentSectorId != null) renderGalaxy(galaxyMap.sectors.getValue(currentSectorId).location) @@ -59,6 +77,8 @@ private abstract class MapPan(val scope: CoroutineScope) { private var prevMouseX = 0.0 private var prevMouseY = 0.0 + abstract fun moveTo(newX: Double, newY: Double) + abstract fun handleClick(currX: Double, currY: Double): MapObjectPtr? abstract fun handleDrag(currX: Double, currY: Double, prevX: Double, prevY: Double) @@ -68,7 +88,7 @@ private abstract class MapPan(val scope: CoroutineScope) { if (ev.ctrlKey) renderInNewTab(target) else - scope.openPtr(target, sectorId) + scope.openPtr(target, sectorId, false) } private fun onAuxClick(ev: MouseEvent) { @@ -112,7 +132,7 @@ private abstract class MapPan(val scope: CoroutineScope) { val target = handleClick(ev.center.x.toDouble(), ev.center.y.toDouble()) ?: return - scope.openPtr(target, sectorId) + scope.openPtr(target, sectorId, false) } private fun onHammerPress(ev: HammerInput) { @@ -186,6 +206,11 @@ private class GalaxyMapPan(scope: CoroutineScope) : MapPan(scope) { var x = 0.0 var y = 0.0 + override fun moveTo(newX: Double, newY: Double) { + x = newX + y = newY + } + override fun handleClick(currX: Double, currY: Double): MapObjectPtr? { val worldX = (currX - x) / GALAXY_MAP_SIZE_FACTOR val worldY = (currY - y) / GALAXY_MAP_SIZE_FACTOR @@ -322,8 +347,8 @@ private fun CoroutineScope.renderGalaxy(panPosition: Vector2? = null) { setCurrentLocation(GalaxyPtr) val pan = GalaxyMapPan() - preparePan(pan, panPosition) + mapPan = pan val galaxySvg = document.create.ksvg { viewBox = "0 0 ${galaxyMap.background.size.x.toDouble()} ${galaxyMap.background.size.y.toDouble()}" @@ -505,6 +530,11 @@ private fun CoroutineScope.renderGalaxy(panPosition: Vector2? = null) { private class SectorMapPan(private val camera: PerspectiveCamera, override val sectorId: String, private val sector: SectorMap, private val interSectorLinks: List, scope: CoroutineScope) : MapPan(scope) { private val rayCaster = Raycaster() + override fun moveTo(newX: Double, newY: Double) { + camera.position.set(newX, 110.851252, newY + 64) + camera.updateMatrixWorld(true) + } + override fun handleClick(currX: Double, currY: Double): MapObjectPtr? { rayCaster.setFromCamera(configure { x = (currX / window.innerWidth * 2) - 1 @@ -686,21 +716,11 @@ private fun CoroutineScope.renderSector(sectorId: String, initialSelection: Sect val interSectorLinks = mutableListOf() - val cameraPos = when (initialSelection) { - SectorMapSelection.NoSelection -> Vector2(0, 0) - is SectorMapSelection.SelectedSystem -> sector.starSystems.getValue(initialSelection.system).location - is SectorMapSelection.SelectedBody -> { - val system = sector.starSystems.getValue(initialSelection.system) - Vector2().copy(system.location).add(system.celestialBodies.getValue(initialSelection.body).location) - } - } - val camera = PerspectiveCamera(69, window.aspectRatio, 1, 10000) camera.rotateX(-PI / 3) - camera.position.set(cameraPos.x, 110.851252, cameraPos.y.toDouble() + 64) - camera.updateMatrixWorld(true) val pan = SectorMapPan(camera, sectorId, sector, interSectorLinks) + pan.moveCameraToSelection(sector, initialSelection) val glCanvas = document.create.canvas(content = "") glCanvas.width = (window.innerWidth * window.devicePixelRatio).roundToInt() @@ -713,6 +733,8 @@ private fun CoroutineScope.renderSector(sectorId: String, initialSelection: Sect powerPreference = "high-performance" }) + mapPan = pan + val cssCanvas = document.create.div { style = "pointer-events:none;position:fixed;top:0;left:0;width:100vw;height:100vh" } @@ -911,6 +933,19 @@ private fun CoroutineScope.renderSector(sectorId: String, initialSelection: Sect } } +context(CoroutineScope) +@HtmlTagMarker +private inline fun FlowOrInteractiveOrPhrasingContent.a(ptr: MapObjectPtr, currentSectorId: String?, crossinline block: A.() -> Unit = {}) { + a(href = ptr.toUrl().href) { + onClickFunction = { ev -> + ev.preventDefault() + openPtr(ptr, currentSectorId, true) + } + + block() + } +} + private fun CoroutineScope.renderLore(ptr: MapObjectPtr) { val loreBar = document.getElementById("lore-bar")!!.unsafeCast() @@ -925,12 +960,7 @@ private fun CoroutineScope.renderLore(ptr: MapObjectPtr) { is SectorPtr -> { val sector = galaxyMap.sectors.getValue(ptr.sector) p { - a(href = GalaxyPtr.toUrl().href) { - onClickFunction = { ev -> - ev.preventDefault() - openPtr(GalaxyPtr, ptr.sector) - } - + a(GalaxyPtr, ptr.sector) { +galaxyMap.universeTitle } } @@ -943,22 +973,12 @@ private fun CoroutineScope.renderLore(ptr: MapObjectPtr) { val sector = galaxyMap.sectors.getValue(ptr.sector) val system = sector.starSystems.getValue(ptr.system) p { - a(href = GalaxyPtr.toUrl().href) { - onClickFunction = { ev -> - ev.preventDefault() - openPtr(GalaxyPtr, ptr.sector) - } - + a(GalaxyPtr, ptr.sector) { +galaxyMap.universeTitle } +" > " val sectorPtr = SectorPtr(ptr.sector) - a(href = sectorPtr.toUrl().href) { - onClickFunction = { ev -> - ev.preventDefault() - openPtr(sectorPtr, ptr.sector) - } - + a(sectorPtr, ptr.sector) { +sector.name } } @@ -977,32 +997,17 @@ private fun CoroutineScope.renderLore(ptr: MapObjectPtr) { val system = sector.starSystems.getValue(ptr.system) val body = system.celestialBodies.getValue(ptr.body) p { - a(href = GalaxyPtr.toUrl().href) { - onClickFunction = { ev -> - ev.preventDefault() - openPtr(GalaxyPtr, ptr.sector) - } - + a(GalaxyPtr, ptr.sector) { +galaxyMap.universeTitle } +" > " val sectorPtr = SectorPtr(ptr.sector) - a(href = sectorPtr.toUrl().href) { - onClickFunction = { ev -> - ev.preventDefault() - openPtr(sectorPtr, ptr.sector) - } - + a(sectorPtr, ptr.sector) { +sector.name } +" > " val starSystemPtr = StarSystemPtr(ptr.sector, ptr.system) - a(href = starSystemPtr.toUrl().href) { - onClickFunction = { ev -> - ev.preventDefault() - openPtr(starSystemPtr, ptr.sector) - } - + a(starSystemPtr, ptr.sector) { +system.name } } @@ -1041,12 +1046,7 @@ private fun CoroutineScope.renderLore(ptr: MapObjectPtr) { for ((sectorId, sector) in sectorsList) li { val sectorPtr = SectorPtr(sectorId) - a(href = sectorPtr.toUrl().href) { - onClickFunction = { ev -> - ev.preventDefault() - renderMap(sectorPtr) - } - + a(sectorPtr, null) { +sector.name } } @@ -1066,12 +1066,7 @@ private fun CoroutineScope.renderLore(ptr: MapObjectPtr) { for ((systemId, system) in systemsList) li { val systemPtr = StarSystemPtr(ptr.sector, systemId) - a(href = systemPtr.toUrl().href) { - onClickFunction = { ev -> - ev.preventDefault() - renderMap(systemPtr) - } - + a(systemPtr, ptr.sector) { +system.name } } @@ -1093,12 +1088,7 @@ private fun CoroutineScope.renderLore(ptr: MapObjectPtr) { for ((bodyId, body) in bodiesList) li { val bodyPtr = CelestialBodyPtr(ptr.sector, ptr.system, bodyId) - a(href = bodyPtr.toUrl().href) { - onClickFunction = { ev -> - ev.preventDefault() - renderMap(CelestialBodyPtr(ptr.sector, ptr.system, bodyId)) - } - + a(bodyPtr, ptr.sector) { +body.name } } diff --git a/src/mapMain/kotlin/info/mechyrdia/mapviewer/utils.kt b/src/mapMain/kotlin/info/mechyrdia/mapviewer/utils.kt index 772756d..d721cf8 100644 --- a/src/mapMain/kotlin/info/mechyrdia/mapviewer/utils.kt +++ b/src/mapMain/kotlin/info/mechyrdia/mapviewer/utils.kt @@ -1,6 +1,7 @@ package info.mechyrdia.mapviewer import com.github.nwillc.ksvg.RenderMode +import externals.threejs.Vector2 import kotlinx.browser.window import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.flow.Flow @@ -27,6 +28,9 @@ suspend fun awaitAnimationFrame(): Double = suspendCancellableCoroutine { contin } } +operator fun Vector2.component1() = x.toDouble() +operator fun Vector2.component2() = y.toDouble() + val deltaTimeFlow: Flow get() = flow { var prevTime = awaitAnimationFrame() -- 2.25.1