/* * This file is part of BlueMap, licensed under the MIT License (MIT). * * Copyright (c) Blue (Lukas Rieger) * Copyright (c) contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ import {Marker} from "./markers/Marker"; import {CSS2DObject} from "./util/CSS2DRenderer"; import {animate, htmlToElement} from "./util/Utils"; import {BoxGeometry, MeshBasicMaterial, Mesh, Vector2} from "three"; import {i18n} from "../i18n"; export class PopupMarker extends Marker { constructor(id, appState, events) { super(id); this.data.type = "popup"; this.data.label = "Last Map Interaction"; this.data.listed = false; this.appState = appState; this.events = events; this.visible = false; this.elementObject = new CSS2DObject(htmlToElement(`
Test
`)); this.elementObject.position.set(0.5, 1, 0.5); this.elementObject.disableDepthTest = true; this.addEventListener( 'removed', () => { if (this.element.parentNode) this.element.parentNode.removeChild(this.element); }); let cubeGeo = new BoxGeometry(1.01, 1.01, 1.01).translate(0.5, 0.5, 0.5); let cubeMaterial = new MeshBasicMaterial( {color: 0xffffff, opacity: 0.5, transparent: true} ); this.cube = new Mesh(cubeGeo, cubeMaterial); this.cube.onClick = evt => this.onClick(evt); this.add(this.elementObject); this.add(this.cube); this.animation = null; this.events.addEventListener('bluemapMapInteraction', this.onMapInteraction); window.addEventListener("mousedown", this.removeHandler); window.addEventListener("touchstart", this.removeHandler, { passive: true }); window.addEventListener("keydown", this.removeHandler); window.addEventListener("mousewheel", this.removeHandler); } onClick(event) { return true; } onMapInteraction = evt => { let isHires = true; let int = evt.detail.hiresHit; if (evt.detail.lowresHits) { for (let i = 0; i < evt.detail.lowresHits.length; i++) { if (!int) { isHires = false; int = evt.detail.lowresHits[i]; } else break; } } if (!int) return; this.position .copy(int.pointOnLine || int.point) .add(evt.detail.ray.direction.clone().multiplyScalar(0.05)) .floor(); //this.elementObject.position //.copy(evt.detail.intersection.pointOnLine || evt.detail.intersection.point) //.sub(this.position); if (isHires) { this.element.innerHTML = `
${i18n.t("blockTooltip.block")}:
x: ${this.position.x}
y: ${this.position.y}
z: ${this.position.z}
`; } else { this.element.innerHTML = `
${i18n.t("blockTooltip.position")}:
x: ${this.position.x}
z: ${this.position.z}
`; } if (this.appState.debug) { let chunkCoords = this.position.clone().divideScalar(16).floor(); let regionCoords = new Vector2(this.position.x, this.position.z).divideScalar(512).floor(); let regionFile = `r.${regionCoords.x}.${regionCoords.y}.mca`; this.element.innerHTML += `
${i18n.t("blockTooltip.chunk")}:
x: ${chunkCoords.x}
y: ${chunkCoords.y}
z: ${chunkCoords.z}

${i18n.t("blockTooltip.region.region")}:
x: ${regionCoords.x}
z: ${regionCoords.y}
${i18n.t("blockTooltip.region.file")}: ${regionFile}
`; } if (this.appState.debug) { let faceIndex = int.faceIndex; let attributes = int.object.geometry.attributes; if (attributes.sunlight && attributes.blocklight) { let sunlight = attributes.sunlight.array[faceIndex * 3]; let blocklight = attributes.blocklight.array[faceIndex * 3]; this.element.innerHTML += `
${i18n.t("blockTooltip.light.light")}:
${i18n.t("blockTooltip.light.sun")}: ${sunlight}
${i18n.t("blockTooltip.light.block")}: ${blocklight}
`; } } if (this.appState.debug) { let info = ""; if (isHires) { let hrPath = evt.detail.hiresHit?.object?.userData?.tileUrl; info += `
${hrPath}
`; } if (evt.detail.lowresHits) { for (let i = 0; i < evt.detail.lowresHits.length; i++) { let lrPath = evt.detail.lowresHits[i]?.object?.userData?.tileUrl; if (lrPath) info += `
${lrPath}
`; } } this.element.innerHTML += `
${info}
`; } if (this.appState.debug){ console.debug("Clicked Position Data:", evt.detail); } this.open(); }; open() { if (this.animation) this.animation.cancel(); this.visible = true; this.cube.visible = true; let targetOpacity = 1; this.element.style.opacity = "0"; this.animation = animate(progress => { this.element.style.opacity = (progress * targetOpacity).toString(); }, 300); } removeHandler = evt => { if (evt.composedPath().includes(this.element)) return; this.close(); } close() { if (this.animation) this.animation.cancel(); this.cube.visible = false; let startOpacity = parseFloat(this.element.style.opacity); this.animation = animate(progress => { this.element.style.opacity = (startOpacity - progress * startOpacity).toString(); }, 300, finished => { if (finished) this.visible = false; }); } /** * @returns {Element} */ get element() { return this.elementObject.element.getElementsByTagName("div")[0]; } dispose() { super.dispose(); if (this.element.parentNode) this.element.parentNode.removeChild(this.element); } }