244 lines
9.4 KiB
JavaScript
244 lines
9.4 KiB
JavaScript
/*
|
|
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
|
*
|
|
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
|
* 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(`<div id="bm-marker-${this.data.id}" class="bm-marker-${this.data.type}">Test</div>`));
|
|
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 = `
|
|
<div class="group">
|
|
<div class="label">${i18n.t("blockTooltip.block")}:</div>
|
|
<div class="content">
|
|
<div class="entry"><span class="label">x: </span><span class="value">${this.position.x}</span></div>
|
|
<div class="entry"><span class="label">y: </span><span class="value">${this.position.y}</span></div>
|
|
<div class="entry"><span class="label">z: </span><span class="value">${this.position.z}</span></div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
} else {
|
|
this.element.innerHTML = `
|
|
<div class="group">
|
|
<div class="label">${i18n.t("blockTooltip.position")}:</div>
|
|
<div class="content">
|
|
<div class="entry"><span class="label">x: </span><span class="value">${this.position.x}</span></div>
|
|
<div class="entry"><span class="label">z: </span><span class="value">${this.position.z}</span></div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
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 += `
|
|
<hr>
|
|
<div class="group">
|
|
<div class="label">${i18n.t("blockTooltip.chunk")}:</div>
|
|
<div class="content">
|
|
<div class="entry"><span class="label">x: </span><span class="value">${chunkCoords.x}</span></div>
|
|
<div class="entry"><span class="label">y: </span><span class="value">${chunkCoords.y}</span></div>
|
|
<div class="entry"><span class="label">z: </span><span class="value">${chunkCoords.z}</span></div>
|
|
</div>
|
|
</div>
|
|
<hr>
|
|
<div class="group">
|
|
<div class="label">${i18n.t("blockTooltip.region.region")}:</div>
|
|
<div class="content">
|
|
<div class="entry"><span class="label">x: </span><span class="value">${regionCoords.x}</span></div>
|
|
<div class="entry"><span class="label">z: </span><span class="value">${regionCoords.y}</span></div>
|
|
</div>
|
|
<div class="content">
|
|
<div class="entry"><span class="label">${i18n.t("blockTooltip.region.file")}: </span><span class="value">${regionFile}</span></div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
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 += `
|
|
<hr>
|
|
<div class="group">
|
|
<div class="label">${i18n.t("blockTooltip.light.light")}:</div>
|
|
<div class="content">
|
|
<div class="entry"><span class="label">${i18n.t("blockTooltip.light.sun")}: </span><span class="value">${sunlight}</span></div>
|
|
<div class="entry"><span class="label">${i18n.t("blockTooltip.light.block")}: </span><span class="value">${blocklight}</span></div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
if (this.appState.debug) {
|
|
let info = "";
|
|
|
|
if (isHires) {
|
|
let hrPath = evt.detail.hiresHit?.object?.userData?.tileUrl;
|
|
info += `<div>${hrPath}</div>`;
|
|
}
|
|
|
|
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 += `<div>${lrPath}</div>`;
|
|
}
|
|
}
|
|
|
|
this.element.innerHTML += `
|
|
<hr>
|
|
<div class="files">
|
|
${info}
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
} |