Replace the webapp with the new BlueMapVue project and adapt the build-script

This commit is contained in:
Blue (Lukas Rieger) 2021-03-18 22:55:07 +01:00
parent f520833099
commit 2cd2606f58
No known key found for this signature in database
GPG Key ID: 904C4995F9E1F800
68 changed files with 52 additions and 4996 deletions

3
.gitignore vendored
View File

@ -36,12 +36,11 @@ run/*
*/.idea
node_modules/
package-lock.json
*.launch
# exclude generated resource
BlueMapCore/src/main/resources/de/bluecolored/bluemap/webroot.zip
BlueMapCommon/src/main/resources/de/bluecolored/bluemap/webapp.zip
BlueMapCore/src/main/resources/de/bluecolored/bluemap/*/resourceExtensions.zip
#exclude-test-data

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "BlueMapAPI"]
path = BlueMapAPI
url = https://github.com/BlueMap-Minecraft/BlueMapAPI
[submodule "BlueMapVue"]
path = BlueMapCommon/BlueMapVue
url = https://github.com/BlueMap-Minecraft/BlueMapVue

@ -0,0 +1 @@
Subproject commit b6a6adcf5da0bd7abe2ce7072021b93b3109b708

View File

@ -1,3 +1,7 @@
plugins {
id "com.github.node-gradle.node" version "3.0.0"
}
dependencies {
compile 'com.mojang:brigadier:1.0.17'
@ -5,3 +9,30 @@ dependencies {
compile project(':BlueMapAPI')
}
node {
version = '14.15.5'
download = true
nodeProjectDir = file("BlueMapVue/")
}
task cleanWebapp(type: Delete) {
delete 'BlueMapVue/dist'
}
task buildWebapp(type: NpmTask) {
dependsOn 'cleanWebapp'
dependsOn 'npmInstall'
args = ['run', 'build']
}
task zipWebapp(type: Zip) {
dependsOn 'buildWebapp'
from fileTree('BlueMapVue/dist/')
archiveName 'webapp.zip'
destinationDir(file('src/main/resources/de/bluecolored/bluemap/'))
outputs.upToDateWhen { false }
}
//always update the zip before build
processResources.dependsOn(zipWebapp)

View File

@ -55,7 +55,6 @@ import de.bluecolored.bluemap.core.render.hires.HiresModelManager;
import de.bluecolored.bluemap.core.render.lowres.LowresModelManager;
import de.bluecolored.bluemap.core.resourcepack.ParseResourceException;
import de.bluecolored.bluemap.core.resourcepack.ResourcePack;
import de.bluecolored.bluemap.core.web.WebFilesManager;
import de.bluecolored.bluemap.core.web.WebSettings;
import de.bluecolored.bluemap.core.world.SlicedWorld;
import de.bluecolored.bluemap.core.world.World;

View File

@ -22,7 +22,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package de.bluecolored.bluemap.core.web;
package de.bluecolored.bluemap.common;
import de.bluecolored.bluemap.core.logger.Logger;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
@ -31,24 +34,20 @@ import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.io.FileUtils;
public class WebFilesManager {
private File webRoot;
private final File webRoot;
public WebFilesManager(File webRoot) {
this.webRoot = webRoot;
}
public boolean needsUpdate() {
if (!new File(webRoot, "index.html").exists()) return true;
return false;
return !new File(webRoot, "index.html").exists();
}
public void updateFiles() throws IOException {
URL fileResource = getClass().getResource("/de/bluecolored/bluemap/webroot.zip");
URL fileResource = getClass().getResource("/de/bluecolored/bluemap/webapp.zip");
File tempFile = File.createTempFile("bluemap_webroot_extraction", null);
try {
@ -57,15 +56,21 @@ public class WebFilesManager {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while(entries.hasMoreElements()) {
ZipEntry zipEntry = entries.nextElement();
if (zipEntry.isDirectory()) new File(webRoot, zipEntry.getName()).mkdirs();
else {
if (zipEntry.isDirectory()) {
File dir = new File(webRoot, zipEntry.getName());
if (!dir.mkdirs()) {
Logger.global.logWarning("Failed to create directory: " + dir);
}
} else {
File target = new File(webRoot, zipEntry.getName());
FileUtils.copyInputStreamToFile(zipFile.getInputStream(zipEntry), target);
}
}
}
} finally {
tempFile.delete();
if (!tempFile.delete()) {
Logger.global.logWarning("Failed to delete file: " + tempFile);
}
}
}

View File

@ -1,7 +1,3 @@
plugins {
id 'com.moowork.node' version '1.3.1'
}
dependencies {
compile 'com.github.ben-manes.caffeine:caffeine:2.8.5'
compile 'com.google.code.gson:gson:2.8.0'
@ -25,46 +21,10 @@ processResources {
}
}
node {
version = '12.14.1'
download = true
}
license {
exclude('**/AABB.java')
}
task fixPackageLock() {
if (!file("./package-lock.json").exists()) {
file("./package-lock.json").text = ""
}
}
task cleanWebroot(type: Delete) {
delete 'build/generated/webroot/'
}
// Run WebPack build to generate resources into the generated resources
task webpackWebroot(type: NpmTask) {
args = ['run', 'build']
}
task zipWebroot(type: Zip) {
from fileTree('build/generated/webroot/')
archiveName 'webroot.zip'
destinationDir(file('src/main/resources/de/bluecolored/bluemap/'))
outputs.upToDateWhen { false }
}
// removes tmp build directory, build project with webpack, zip contents for the shaded jar
task buildWebroot {
dependsOn 'fixPackageLock'
dependsOn 'npmInstall'
dependsOn 'cleanWebroot'
dependsOn 'webpackWebroot'
dependsOn 'zipWebroot'
}
//resource Extensions
task zipResourceExtensions {
dependsOn 'zipResourceExtensions1_12'
@ -102,5 +62,4 @@ task zipResourceExtensions1_16(type: Zip) {
}
//always update the zip before build
processResources.dependsOn(buildWebroot)
processResources.dependsOn(zipResourceExtensions)

View File

@ -1,43 +0,0 @@
{
"name": "bluemap",
"description": "BlueMap is a tool that generates 3d-maps of your Minecraft worlds and displays them in your browser.",
"private": true,
"repository": {
"type": "git",
"url": "git+https://github.com/BlueMap-Minecraft/BlueMap.git"
},
"keywords": [
"minecraft"
],
"author": "Blue",
"license": "MIT",
"bugs": {
"url": "https://github.com/BlueMap-Minecraft/BlueMap/issues"
},
"homepage": "https://github.com/BlueMap-Minecraft/BlueMap#readme",
"dependencies": {
"jquery": "^3.4.1",
"three": "^0.94.0",
"hammerjs": "^2.0.8"
},
"devDependencies": {
"css-loader": "^3.4.2",
"fibers": "^4.0.2",
"file-loader": "^5.0.2",
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.9.0",
"node-sass": "^4.13.0",
"sass": "^1.24.4",
"sass-loader": "^8.0.2",
"ts-loader": "^6.2.1",
"typescript": "^3.7.4",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.1"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode production",
"start": "webpack-dev-server --watch --mode development"
}
}

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="30px" height="30px" viewBox="0 0 30 30" enable-background="new 0 0 30 30" xml:space="preserve">
<path fill="#333333" d="M25.004,15c0,0.807-0.75,1.461-1.676,1.461H6.671c-0.925,0-1.674-0.654-1.674-1.461l0,0
c0-0.807,0.749-1.461,1.674-1.461h16.657C24.254,13.539,25.004,14.193,25.004,15L25.004,15z"/>
<path fill="#333333" d="M25.004,20.706c0,0.807-0.75,1.461-1.676,1.461H6.671c-0.925,0-1.674-0.654-1.674-1.461l0,0
c0-0.807,0.749-1.461,1.674-1.461h16.657C24.254,19.245,25.004,19.899,25.004,20.706L25.004,20.706z"/>
<path fill="#333333" d="M25.004,9.294c0,0.806-0.75,1.46-1.676,1.46H6.671c-0.925,0-1.674-0.654-1.674-1.46l0,0
c0-0.807,0.749-1.461,1.674-1.461h16.657C24.254,7.833,25.004,8.487,25.004,9.294L25.004,9.294z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="30px" height="30px" viewBox="0 0 30 30" enable-background="new 0 0 30 30" xml:space="preserve">
<g>
<g>
<path fill="#333333" d="M19.674,15.998L15,25.749l-4.674-9.751h2.479l1.293,2.698L15,20.578l0.902-1.881l1.293-2.698H19.674
M21.263,14.998h-4.697L15,18.264l-1.565-3.266H8.737L15,28.063L21.263,14.998L21.263,14.998z"/>
</g>
<g>
<polygon fill="#333333" points="16.88,14.502 15,10.579 13.12,14.502 9.531,14.502 15,3.094 20.469,14.502 "/>
<path fill="#333333" d="M15,4.251l4.674,9.751h-2.479l-1.293-2.698L15,9.422l-0.902,1.881l-1.293,2.698h-2.479L15,4.251 M15,1.938
L8.737,15.002h4.697L15,11.736l1.565,3.266h4.697L15,1.938L15,1.938z"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="30px" height="30px" viewBox="0 0 30 30" enable-background="new 0 0 30 30" xml:space="preserve">
<path fill="#333333" d="M24.187,15.349c0.8-0.141,1.183-0.315,0.861-2.14c-0.32-1.827-0.732-1.831-1.536-1.691l-1.56,0.275
c-0.197-0.429-0.434-0.836-0.704-1.218l1.02-1.215c0.52-0.621,0.705-1.001-0.716-2.192c-1.42-1.193-1.737-0.933-2.262-0.308
l-1.022,1.217c-0.421-0.199-0.862-0.359-1.321-0.48v-1.59c-0.002-0.811-0.106-1.221-1.96-1.221c-1.854,0-1.93,0.403-1.93,1.221
v1.589c-0.459,0.12-0.899,0.28-1.32,0.479l-1.021-1.216C10.193,6.238,9.85,5.991,8.43,7.182c-1.421,1.192-1.219,1.55-0.696,2.175
l1.019,1.215c-0.271,0.383-0.505,0.79-0.703,1.219L6.49,11.515c-0.798-0.14-1.22-0.109-1.542,1.717
c-0.323,1.827,0.062,1.971,0.866,2.114l1.559,0.275c0.039,0.476,0.123,0.938,0.244,1.385l-1.371,0.792
c-0.701,0.405-1.004,0.701-0.077,2.307c0.927,1.606,1.315,1.469,2.022,1.063l1.365-0.787c0.332,0.335,0.695,0.637,1.083,0.907
l-0.54,1.481c-0.277,0.761-0.319,1.181,1.422,1.816c1.743,0.635,1.952,0.28,2.232-0.486l0.539-1.479
c0.233,0.02,0.469,0.035,0.708,0.035c0.238,0,0.472-0.016,0.707-0.035l0.537,1.481c0.279,0.761,0.517,1.108,2.257,0.475
c1.743-0.632,1.677-1.038,1.398-1.805l-0.538-1.482c0.388-0.271,0.752-0.572,1.083-0.907l1.366,0.789
c0.699,0.405,1.106,0.519,2.033-1.086c0.929-1.606,0.616-1.873-0.089-2.283l-1.371-0.791c0.122-0.448,0.206-0.912,0.245-1.388
L24.187,15.349z M15,19.492c-2.484,0-4.498-2.013-4.498-4.497c0-2.483,2.013-4.497,4.498-4.497s4.496,2.014,4.496,4.497
C19.496,17.48,17.484,19.492,15,19.492z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="30px" height="30px" viewBox="0 0 30 30" enable-background="new 0 0 30 30" xml:space="preserve">
<path fill="#333333" d="M17.011,19.722c-3.778-1.613-5.533-5.982-3.921-9.76c0.576-1.348,1.505-2.432,2.631-3.204
c-3.418-0.243-6.765,1.664-8.186,4.992c-1.792,4.197,0.159,9.053,4.356,10.844c3.504,1.496,7.462,0.377,9.717-2.476
C20.123,20.465,18.521,20.365,17.011,19.722z"/>
<circle fill="#333333" cx="5.123" cy="7.64" r="1.196"/>
<circle fill="#333333" cx="23.178" cy="5.249" r="1.195"/>
<circle fill="#333333" cx="20.412" cy="13.805" r="1.195"/>
<circle fill="#333333" cx="25.878" cy="23.654" r="1.195"/>
</svg>

Before

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="50px" height="50px" viewBox="0 0 50 50" enable-background="new 0 0 50 50" xml:space="preserve">
<g>
<path fill="#FFFFFF" d="M37.468,17.123C37.468,29.596,25,45.346,25,45.346s-12.468-14.93-12.468-28.223
c0-6.885,5.581-12.468,12.468-12.468C31.885,4.655,37.468,10.237,37.468,17.123z"/>
</g>
<g>
<path fill="#333333" d="M26.901,12.559c0.034,1.046-0.732,1.885-1.954,1.885c-1.083,0-1.85-0.838-1.85-1.885
c0-1.082,0.804-1.92,1.918-1.92C26.169,10.639,26.901,11.478,26.901,12.559z M23.464,29.063l0.017-11.757h3.072l-0.018,11.757
H23.464z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 919 B

View File

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
<title>BlueMap</title>
</head>
<body>
<div id="map-container"></div>
</body>
</html>

View File

@ -1,613 +0,0 @@
/*
* 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 $ from 'jquery';
import {
BackSide,
BufferGeometryLoader,
ClampToEdgeWrapping,
SphereGeometry,
FileLoader,
FrontSide,
Mesh,
NearestFilter,
NearestMipMapLinearFilter,
PerspectiveCamera,
Scene,
ShaderMaterial,
Texture,
VertexColors,
WebGLRenderer,
Vector3,
} from 'three';
import { CSS2DRenderer } from './hud/CSS2DRenderer';
import UI from './ui/UI.js';
import Controls from './Controls.js';
import TileManager from './TileManager.js';
import HIRES_VERTEX_SHADER from './shaders/HiresVertexShader.js';
import HIRES_FRAGMENT_SHADER from './shaders/HiresFragmentShader.js';
import LOWRES_VERTEX_SHADER from './shaders/LowresVertexShader.js';
import LOWRES_FRAGMENT_SHADER from './shaders/LowresFragmentShader.js';
import SKY_VERTEX_SHADER from './shaders/SkyVertexShader.js';
import SKY_FRAGMENT_SHADER from './shaders/SkyFragmentShader.js';
import { stringToImage, pathFromCoords } from './utils.js';
import {cachePreventionNr, getCookie, setCookie} from "./utils";
export default class BlueMap {
constructor(element, dataRoot = "data/", liveApiRoot = "live/") {
this.element = $('<div class="bluemap-container"></div>').appendTo(element)[0];
this.dataRoot = dataRoot;
this.liveApiRoot = liveApiRoot;
this.locationHash = '';
this.cacheSuffix = '';
this.hiresViewDistance = 160;
this.lowresViewDistance = 3200;
this.targetSunLightStrength = 1;
this.sunLightStrength = {
value: this.targetSunLightStrength
};
this.mobSpawnOverlay = {
value: false
};
this.ambientLight = {
value: 0
};
this.skyColor = {
value: new Vector3(0, 0, 0)
};
this.debugInfo = this.loadUserSetting("debugInfo", true);
this.fileLoader = new FileLoader();
this.blobLoader = new FileLoader();
this.blobLoader.setResponseType('blob');
this.bufferGeometryLoader = new BufferGeometryLoader();
this.ui = new UI(this);
this.loadingNoticeElement = $('<div>loading...</div>').appendTo($(this.element));
window.onerror = this.onLoadError;
this.initStage();
this.controls = new Controls(this.camera, this.element, this.hiresScene);
this.loadSettings().then(async () => {
await this.loadHiresMaterial();
await this.loadLowresMaterial();
this.debugInfo = false;
this.loadUserSettings();
this.handleContainerResize();
this.changeMap(this.maps[0], false);
await this.ui.load();
this.start();
}).catch(error => {
this.onLoadError("Initialization: " + (error ? error.toString() : "unknown"));
});
}
reloadMap() {
if (this.hiresTileManager !== undefined){
this.hiresTileManager.removeAllTiles();
this.hiresTileManager.update();
}
if (this.lowresTileManager !== undefined){
this.lowresTileManager.removeAllTiles();
this.lowresTileManager.update();
}
}
changeMap(map, loadTiles = true) {
if (this.debugInfo) console.debug("changing map: ", map);
if (this.map === map) return;
if (this.hiresTileManager !== undefined) this.hiresTileManager.close();
if (this.lowresTileManager !== undefined) this.lowresTileManager.close();
this.map = map;
let startPos = {
x: this.settings.maps[this.map]["startPos"]["x"],
z: this.settings.maps[this.map]["startPos"]["z"]
};
this.ambientLight.value = this.settings.maps[this.map]["ambientLight"];
this.skyColor.value.set(
this.settings.maps[this.map]["skyColor"].r,
this.settings.maps[this.map]["skyColor"].g,
this.settings.maps[this.map]["skyColor"].b
);
this.controls.setTileSize(this.settings.maps[this.map]['hires']['tileSize']);
this.controls.resetPosition();
this.controls.targetPosition.set(startPos.x, this.controls.targetPosition.y, startPos.z);
this.controls.position.copy(this.controls.targetPosition);
this.lowresTileManager = new TileManager(
this,
this.lowresViewDistance,
this.loadLowresTile,
this.lowresScene,
this.settings.maps[this.map]['lowres']['tileSize'],
this.settings.maps[this.map]['lowres']['translate'],
startPos
);
this.hiresTileManager = new TileManager(
this,
this.hiresViewDistance,
this.loadHiresTile,
this.hiresScene,
this.settings.maps[this.map]['hires']['tileSize'],
this.settings.maps[this.map]['hires']['translate'],
startPos
);
if (loadTiles) {
this.lowresTileManager.update();
this.hiresTileManager.update();
}
document.dispatchEvent(new Event('bluemap-map-change'));
}
loadLocationHash(smooth = false) {
let hashVars = window.location.hash.substring(1).split(':');
if (hashVars.length >= 1){
if (this.settings.maps[hashVars[0]] !== undefined && this.map !== hashVars[0]){
this.changeMap(hashVars[0]);
}
}
if (hashVars.length >= 3){
let x = parseInt(hashVars[1]);
let z = parseInt(hashVars[2]);
if (!isNaN(x) && !isNaN(z)){
this.controls.targetPosition.x = x + 0.5;
this.controls.targetPosition.z = z + 0.5;
}
}
if (hashVars.length >= 6){
let dir = parseFloat(hashVars[3]);
let dist = parseFloat(hashVars[4]);
let angle = parseFloat(hashVars[5]);
if (!isNaN(dir)) this.controls.targetDirection = dir;
if (!isNaN(dist)) this.controls.targetDistance = dist;
if (!isNaN(angle)) this.controls.targetAngle = angle;
if (!smooth) {
this.controls.direction = this.controls.targetDirection;
this.controls.distance = this.controls.targetDistance;
this.controls.angle = this.controls.targetAngle;
this.controls.position.copy(this.controls.targetPosition);
}
}
if (hashVars.length >= 7){
let height = parseInt(hashVars[6]);
if (!isNaN(height)){
this.controls.terrainHeight = height;
if (!smooth) {
if (this.controls.position.y < this.controls.terrainHeight) this.controls.position.y = this.controls.terrainHeight;
}
}
}
}
start() {
this.loadingNoticeElement.remove();
this.loadLocationHash();
$(window).on('hashchange', () => {
if (this.locationHash === window.location.hash) return;
this.loadLocationHash(true);
});
this.update();
this.render();
this.lowresTileManager.update();
this.hiresTileManager.update();
}
update = () => {
setTimeout(this.update, 1000);
this.saveUserSettings();
this.lowresTileManager.setPosition(this.controls.targetPosition);
if (this.camera.position.y < 400) {
this.hiresTileManager.setPosition(this.controls.targetPosition);
}
let newHash =
'#' + this.map
+ ':' + Math.floor(this.controls.targetPosition.x)
+ ':' + Math.floor(this.controls.targetPosition.z)
+ ':' + Math.round(this.controls.targetDirection * 100) / 100
+ ':' + Math.round(this.controls.targetDistance * 100) / 100
+ ':' + Math.ceil(this.controls.targetAngle * 100) / 100
+ ':' + Math.floor(this.controls.terrainHeight);
// only update hash when changed
if (window.location.hash !== newHash) {
// but wait until it has finished changing (update when camera is no longer moving, to reduce the number of updates and history spam)
if (this.locationHash === newHash) {
history.replaceState(undefined, undefined, this.locationHash);
}
this.locationHash = newHash;
}
};
render = () => {
requestAnimationFrame(this.render);
//update controls
if (this.controls.update()) this.updateFrame = true;
//update lighting
let targetLight = this.targetSunLightStrength;
if (this.camera.position.y > 400){
targetLight = Math.max(targetLight, 0.5);
}
if (Math.abs(targetLight - this.sunLightStrength.value) > 0.01) {
this.sunLightStrength.value += (targetLight - this.sunLightStrength.value) * 0.1;
this.updateFrame = true;
}
//don't render if nothing has changed
if (!this.updateFrame) return;
this.updateFrame = false;
//render event
document.dispatchEvent(new Event('bluemap-update-frame'));
//render
this.skyboxCamera.rotation.copy(this.camera.rotation);
this.skyboxCamera.updateProjectionMatrix();
this.renderer.clear();
this.renderer.render(this.skyboxScene, this.skyboxCamera);
this.renderer.clearDepth();
this.renderer.render(this.lowresScene, this.camera);
this.renderer.clearDepth();
if (this.camera.position.y < 400) {
this.renderer.render(this.hiresScene, this.camera);
}
this.renderer.render(this.shapeScene, this.camera);
this.hudRenderer.render(this.hudScene, this.camera);
};
handleContainerResize = () => {
this.camera.aspect = this.element.clientWidth / this.element.clientHeight;
this.camera.updateProjectionMatrix();
this.skyboxCamera.aspect = this.element.clientWidth / this.element.clientHeight;
this.skyboxCamera.updateProjectionMatrix();
this.renderer.setSize(this.element.clientWidth * this.quality, this.element.clientHeight * this.quality);
$(this.renderer.domElement)
.css('width', this.element.clientWidth)
.css('height', this.element.clientHeight);
this.hudRenderer.setSize(this.element.clientWidth, this.element.clientHeight);
this.updateFrame = true;
};
async loadSettings() {
return new Promise((resolve, reject) => {
this.fileLoader.load(this.dataRoot + 'settings.json?' + cachePreventionNr(), settings => {
try {
this.settings = JSON.parse(settings);
this.maps = [];
for (let map in this.settings.maps) {
if (this.settings["maps"].hasOwnProperty(map) && this.settings.maps[map].enabled) {
this.maps.push(map);
}
}
this.maps.sort((map1, map2) => {
let sort = this.settings.maps[map1].ordinal - this.settings.maps[map2].ordinal;
if (isNaN(sort)) return 0;
return sort;
});
resolve();
} catch (e) {
reject(e);
}
});
});
}
initStage() {
this.updateFrame = true;
this.quality = 1;
this.renderer = new WebGLRenderer({
antialias: true,
sortObjects: true,
preserveDrawingBuffer: true,
logarithmicDepthBuffer: true,
});
this.renderer.autoClear = false;
this.hudRenderer = new CSS2DRenderer();
this.camera = new PerspectiveCamera(75, this.element.scrollWidth / this.element.scrollHeight, 0.1, 10000);
this.camera.updateProjectionMatrix();
this.skyboxCamera = this.camera.clone();
this.skyboxCamera.updateProjectionMatrix();
this.skyboxScene = new Scene();
this.skyboxScene.add(this.createSkybox());
this.lowresScene = new Scene();
this.hiresScene = new Scene();
this.shapeScene = new Scene();
this.hudScene = new Scene();
$(this.renderer.domElement).addClass("map-canvas").appendTo(this.element);
$(this.hudRenderer.domElement).addClass("map-canvas-hud").appendTo(this.element);
this.handleContainerResize();
$(window).resize(this.handleContainerResize);
}
loadUserSettings(){
if (!this.settings["useCookies"]) return;
this.mobSpawnOverlay.value = this.loadUserSetting("mobSpawnOverlay", this.mobSpawnOverlay.value);
this.targetSunLightStrength = this.loadUserSetting("sunLightStrength", this.targetSunLightStrength);
this.quality = this.loadUserSetting("renderQuality", this.quality);
this.hiresViewDistance = this.loadUserSetting("hiresViewDistance", this.hiresViewDistance);
this.lowresViewDistance = this.loadUserSetting("lowresViewDistance", this.lowresViewDistance);
this.controls.settings.zoom.max = this.loadUserSetting("maxZoomDistance", this.controls.settings.zoom.max);
this.cacheSuffix = this.loadUserSetting("cacheSuffix", this.cacheSuffix);
this.debugInfo = this.loadUserSetting("debugInfo", this.debugInfo);
}
saveUserSettings(){
if (!this.settings["useCookies"]) return;
if (this.savedUserSettings === undefined) this.savedUserSettings = {};
this.saveUserSetting("mobSpawnOverlay", this.mobSpawnOverlay.value);
this.saveUserSetting("sunLightStrength", this.targetSunLightStrength);
this.saveUserSetting("renderQuality", this.quality);
this.saveUserSetting("hiresViewDistance", this.hiresViewDistance);
this.saveUserSetting("lowresViewDistance", this.lowresViewDistance);
this.saveUserSetting("maxZoomDistance", this.controls.settings.zoom.max);
this.saveUserSetting("cacheSuffix", this.cacheSuffix);
this.saveUserSetting("debugInfo", this.debugInfo);
}
loadUserSetting(key, defaultValue){
let value = getCookie("bluemap-" + key);
if (value === undefined) return defaultValue;
return value;
}
saveUserSetting(key, value){
if (this.savedUserSettings[key] !== value){
this.savedUserSettings[key] = value;
setCookie("bluemap-" + key, value);
}
}
createSkybox() {
let geometry = new SphereGeometry(10, 10, 10);
let material = new ShaderMaterial({
uniforms: {
sunlightStrength: this.sunLightStrength,
ambientLight: this.ambientLight,
skyColor: this.skyColor,
},
vertexShader: SKY_VERTEX_SHADER,
fragmentShader: SKY_FRAGMENT_SHADER,
side: BackSide
});
return new Mesh(geometry, material);
}
async loadHiresMaterial() {
return new Promise(resolve => {
this.fileLoader.load(this.dataRoot + 'textures.json?' + cachePreventionNr(), textures => {
textures = JSON.parse(textures);
let materials = [];
for (let i = 0; i < textures['textures'].length; i++) {
let t = textures['textures'][i];
let opaque = t['color'][3] === 1;
let transparent = t['transparent'];
let texture = new Texture();
texture.image = stringToImage(t['texture']);
texture.anisotropy = 1;
texture.generateMipmaps = opaque || transparent;
texture.magFilter = NearestFilter;
texture.minFilter = texture.generateMipmaps ? NearestMipMapLinearFilter : NearestFilter;
texture.wrapS = ClampToEdgeWrapping;
texture.wrapT = ClampToEdgeWrapping;
texture.flipY = false;
texture.flatShading = true;
texture.needsUpdate = true;
let uniforms = {
texture: {
type: 't',
value: texture
},
sunlightStrength: this.sunLightStrength,
mobSpawnOverlay: this.mobSpawnOverlay,
ambientLight: this.ambientLight,
};
let material = new ShaderMaterial({
uniforms: uniforms,
vertexShader: HIRES_VERTEX_SHADER,
fragmentShader: HIRES_FRAGMENT_SHADER,
transparent: transparent,
depthWrite: true,
depthTest: true,
vertexColors: VertexColors,
side: FrontSide,
wireframe: false,
});
material.needsUpdate = true;
materials[i] = material;
}
this.hiresMaterial = materials;
resolve();
});
});
}
async loadLowresMaterial() {
this.lowresMaterial = new ShaderMaterial({
uniforms: {
sunlightStrength: this.sunLightStrength,
ambientLight: this.ambientLight,
},
vertexShader: LOWRES_VERTEX_SHADER,
fragmentShader: LOWRES_FRAGMENT_SHADER,
transparent: false,
depthWrite: true,
depthTest: true,
vertexColors: VertexColors,
side: FrontSide,
wireframe: false
});
}
async loadHiresTile(tileX, tileZ) {
let path = this.dataRoot + this.map + '/hires/';
path += pathFromCoords(tileX, tileZ);
path += '.json?' + this.cacheSuffix;
return new Promise((resolve, reject) => {
this.bufferGeometryLoader.load(path, geometry => {
let object = new Mesh(geometry, this.hiresMaterial);
let tileSize = this.settings.maps[this.map]['hires']['tileSize'];
let translate = this.settings.maps[this.map]['hires']['translate'];
let scale = this.settings.maps[this.map]['hires']['scale'];
object.position.set(tileX * tileSize.x + translate.x, 0, tileZ * tileSize.z + translate.z);
object.scale.set(scale.x, 1, scale.z);
resolve(object);
}, () => {
}, reject);
});
}
async loadLowresTile(tileX, tileZ) {
let path = this.dataRoot + this.map + '/lowres/';
path += pathFromCoords(tileX, tileZ);
path += '.json?' + this.cacheSuffix;
return new Promise((reslove, reject) => {
this.bufferGeometryLoader.load(path, geometry => {
let object = new Mesh(geometry, this.lowresMaterial);
let tileSize = this.settings.maps[this.map]['lowres']['tileSize'];
let translate = this.settings.maps[this.map]['lowres']['translate'];
let scale = this.settings.maps[this.map]['lowres']['scale'];
object.position.set(tileX * tileSize.x + translate.x, 0, tileZ * tileSize.z + translate.z);
object.scale.set(scale.x, 1, scale.z);
reslove(object);
}, () => {
}, reject);
})
}
onLoadError = (message, url, line, col) => {
this.loadingNoticeElement.remove();
this.toggleAlert(undefined, `
<div style="max-width: 50rem">
<h1>Error</h1>
<p style="color: red; font-family: monospace">${message}</p>
</div>
`);
};
toggleAlert(id, content) {
let alertBox = $(this.element).find('.alert-box');
if (alertBox.length === 0){
alertBox = $('<div class="alert-box"></div>').appendTo(this.ui.hud);
}
let displayAlert = () => {
let alert = $(`<div class="alert" data-alert-id="${id}" style="display: none;"><div class="close-button"></div>${content}</div>`).appendTo(alertBox);
alert.find('.close-button').click(() => {
alert.stop().fadeOut(200, () => alert.remove());
});
alert.stop().fadeIn(200);
};
if (id !== undefined) {
let sameAlert = alertBox.find(`.alert[data-alert-id=${id}]`);
if (sameAlert.length > 0) {
alertBox.stop().fadeOut(200, () => {
alertBox.html('');
alertBox.show();
});
return;
}
}
let oldAlerts = alertBox.find('.alert');
if (oldAlerts.length > 0){
alertBox.stop().fadeOut(200, () => {
alertBox.html('');
alertBox.show();
displayAlert();
});
return;
}
displayAlert();
}
}

View File

@ -1,440 +0,0 @@
/*
* 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 Softwarevent.
*
* 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 SOFTWARevent.
*/
import $ from 'jquery';
import {
Euler,
Raycaster,
Vector2,
Vector3,
MOUSE
} from 'three';
import Hammer from 'hammerjs';
import { Vector2_ZERO } from './utils.js';
export default class Controls {
static KEYS = {
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40,
ORBIT: MOUSE.RIGHT,
MOVE: MOUSE.LEFT
};
static STATES = {
NONE: -1,
ORBIT: 0,
MOVE: 1,
};
/**
* targetHeightScene and cameraHeightScene are scenes of objects that are checked via raycasting for a height for the target and the camera
*/
constructor(camera, element, heightScene) {
this.settings = {
zoom: {
min: 10,
max: 2000,
speed: 1.5,
smooth: 0.2,
},
move: {
speed: 1.75,
smooth: 0.3,
smoothY: 0.075,
},
tilt: {
max: Math.PI / 2.1,
speed: 1.5,
smooth: 0.3,
},
rotate: {
speed: 1.5,
smooth: 0.3,
}
};
this.camera = camera;
this.element = element;
this.heightScene = heightScene;
this.terrainHeight = 70;
this.raycaster = new Raycaster();
this.rayDirection = new Vector3(0, -1, 0);
this.resetPosition();
this.mouse = new Vector2(0, 0);
this.lastMouse = new Vector2(0, 0);
this.deltaMouse = new Vector2(0, 0);
//variables used to calculate with (to prevent object creation every update)
this.orbitRot = new Euler(0, 0, 0, 'YXZ');
this.cameraPosDelta = new Vector3(0, 0, 0);
this.moveDelta = new Vector2(0, 0);
this.touchStart = new Vector2(0, 0);
this.touchDelta = new Vector2(0, 0);
this.keyStates = {};
this.state = Controls.STATES.NONE;
this.mouseMoved = false;
let canvas = $(this.element).find('canvas').get(0);
// mouse events
window.addEventListener('contextmenu', event => {
event.preventDefault();
}, false);
window.addEventListener('mousemove', this.onMouseMove, false);
canvas.addEventListener('mousedown', this.onMouseDown, false);
window.addEventListener('mouseup', this.onMouseUp, false); //this is on the window instead of the canvas, so if we drag out of the canvas and release the mouse it actually gets released
canvas.addEventListener('wheel', this.onMouseWheel, { passive: true });
window.addEventListener('keydown', this.onKeyDown, false);
window.addEventListener('keyup', this.onKeyUp, false);
// touch events
this.hammer = new Hammer.Manager(canvas);
let touchTap = new Hammer.Tap({ event: 'tap', pointers: 1, taps: 1, threshold: 2 });
let touchMove = new Hammer.Pan({ event: 'move', direction: Hammer.DIRECTION_ALL, threshold: 0 });
let touchTilt = new Hammer.Pan({ event: 'tilt', direction: Hammer.DIRECTION_VERTICAL, pointers: 2, threshold: 0 });
let touchRotate = new Hammer.Rotate({ event: 'rotate', pointers: 2, threshold: 10 });
let touchZoom = new Hammer.Pinch({ event: 'zoom', pointers: 2, threshold: 0 });
touchTilt.recognizeWith(touchRotate);
touchTilt.recognizeWith(touchZoom);
touchRotate.recognizeWith(touchZoom);
this.hammer.add( touchTap );
this.hammer.add( touchMove );
this.hammer.add( touchTilt );
this.hammer.add( touchRotate );
this.hammer.add( touchZoom );
this.hammer.on('movestart', this.onTouchDown);
this.hammer.on('movemove', this.onTouchMove);
this.hammer.on('moveend', this.onTouchUp);
this.hammer.on('movecancel', this.onTouchUp);
this.hammer.on('tiltstart', this.onTouchTiltDown);
this.hammer.on('tiltmove', this.onTouchTiltMove);
this.hammer.on('tiltend', this.onTouchTiltUp);
this.hammer.on('tiltcancel', this.onTouchTiltUp);
this.hammer.on('rotatestart', this.onTouchRotateDown);
this.hammer.on('rotatemove', this.onTouchRotateMove);
this.hammer.on('rotateend', this.onTouchRotateUp);
this.hammer.on('rotatecancel', this.onTouchRotateUp);
this.hammer.on('zoomstart', this.onTouchZoomDown);
this.hammer.on('zoommove', this.onTouchZoomMove);
this.hammer.on('tap', this.onInfoClick);
this.camera.position.set(0, 1000, 0);
this.camera.lookAt(this.position);
this.camera.updateProjectionMatrix();
}
setTileSize(tileSize) {
this.tileSize = tileSize;
}
resetPosition() {
this.position = new Vector3(0, 0, 0);
this.targetPosition = new Vector3(0, 0, 0);
this.distance = 5000;
this.targetDistance = 1000;
this.direction = 0;
this.targetDirection = 0;
this.angle = 0;
this.targetAngle = 0;
}
update() {
this.updateMouseMoves();
let changed = false;
let targetY = Math.max(this.targetPosition.y, this.terrainHeight);
this.position.x += (this.targetPosition.x - this.position.x) * this.settings.move.smooth;
this.position.y += (targetY - this.position.y) * this.settings.move.smoothY;
this.position.z += (this.targetPosition.z - this.position.z) * this.settings.move.smooth;
this.distance += (this.targetDistance - this.distance) * this.settings.zoom.smooth;
let deltaDir = (this.targetDirection - this.direction) * this.settings.rotate.smooth;
this.direction += deltaDir;
changed = changed || Math.abs(deltaDir) > 0.001;
let max = Math.min(this.settings.tilt.max, this.settings.tilt.max - Math.pow(((this.distance - this.settings.zoom.min) / (this.settings.zoom.max - this.settings.zoom.min)) * Math.pow(this.settings.tilt.max, 4), 1/4));
if (this.targetAngle > max) this.targetAngle = max;
if (this.targetAngle < 0.01) this.targetAngle = 0.001;
let deltaAngle = (this.targetAngle - this.angle) * this.settings.tilt.smooth;
this.angle += deltaAngle;
changed = changed || Math.abs(deltaAngle) > 0.001;
let last = this.camera.position.x + this.camera.position.y + this.camera.position.z;
this.orbitRot.set(this.angle, this.direction, 0);
this.cameraPosDelta.set(0, this.distance, 0).applyEuler(this.orbitRot);
this.camera.position.set(this.position.x + this.cameraPosDelta.x, this.position.y + this.cameraPosDelta.y, this.position.z + this.cameraPosDelta.z);
let move = last - (this.camera.position.x + this.camera.position.y + this.camera.position.z);
changed = changed || Math.abs(move) > 0.001;
if (changed) {
this.camera.lookAt(this.position);
this.camera.updateProjectionMatrix();
this.updateHeights();
}
return changed;
}
updateHeights() {
function between(n, min, max) {
return n >= min && n < max;
}
let inTile = (pos, thisPos) => {
return between(pos.x, thisPos.x - this.tileSize.x, thisPos.x) &&
between(pos.z, thisPos.z - this.tileSize.z, thisPos.z);
};
let tileChildren = (targetPos) => {
return this.heightScene.children.filter(child => inTile(child.position, targetPos))
};
// check hight at target
try {
let rayStart = new Vector3(this.targetPosition.x, 300, this.targetPosition.z);
this.raycaster.set(rayStart, this.rayDirection);
this.raycaster.near = 1;
this.raycaster.far = 300;
let intersects = this.raycaster.intersectObjects(tileChildren(this.targetPosition));
if (intersects.length > 0) {
this.terrainHeight = intersects[0].point.y;
}
} catch (ignore){}
// check height at camera
try {
let rayStart = new Vector3(this.camera.position.x, 300, this.camera.position.z);
this.raycaster.set(rayStart, this.rayDirection);
let intersects = this.raycaster.intersectObjects(tileChildren(this.camera.position));
if (intersects.length > 0) {
if (intersects[0].point.y > this.terrainHeight) {
this.terrainHeight = intersects[0].point.y;
}
}
} catch (ignore){}
}
updateMouseMoves = () => {
this.deltaMouse.set(this.lastMouse.x - this.mouse.x, this.lastMouse.y - this.mouse.y);
if (this.keyStates[Controls.KEYS.UP]){
this.moveDelta.y -= 20;
}
if (this.keyStates[Controls.KEYS.DOWN]){
this.moveDelta.y += 20;
}
if (this.keyStates[Controls.KEYS.LEFT]){
this.moveDelta.x -= 20;
}
if (this.keyStates[Controls.KEYS.RIGHT]){
this.moveDelta.x += 20;
}
if (this.state === Controls.STATES.MOVE) {
if (this.deltaMouse.x === 0 && this.deltaMouse.y === 0) return;
this.moveDelta.copy(this.deltaMouse);
}
if (this.moveDelta.x !== 0 || this.moveDelta.y !== 0) {
this.moveDelta.rotateAround(Vector2_ZERO, -this.direction);
this.targetPosition.set(
this.targetPosition.x + (this.moveDelta.x * this.distance / this.element.clientHeight * this.settings.move.speed),
this.targetPosition.y,
this.targetPosition.z + (this.moveDelta.y * this.distance / this.element.clientHeight * this.settings.move.speed)
);
}
if (this.state === Controls.STATES.ORBIT) {
this.targetDirection += (this.deltaMouse.x / this.element.clientHeight * Math.PI);
this.targetAngle += (this.deltaMouse.y / this.element.clientHeight * Math.PI);
}
this.lastMouse.copy(this.mouse);
this.moveDelta.x = 0;
this.moveDelta.y = 0;
};
onMouseWheel = event => {
if (event.deltaY > 0) {
this.targetDistance *= this.settings.zoom.speed;
} else if (event.deltaY < 0) {
this.targetDistance /= this.settings.zoom.speed;
}
if (this.targetDistance < this.settings.zoom.min) this.targetDistance = this.settings.zoom.min;
if (this.targetDistance > this.settings.zoom.max) this.targetDistance = this.settings.zoom.max;
};
onMouseMove = event => {
this.mouse.set(event.clientX, event.clientY);
if (this.state !== Controls.STATES.NONE){
event.preventDefault();
}
};
onMouseDown = event => {
if (this.state !== Controls.STATES.NONE) return;
$(":focus").blur();
switch (event.button) {
case Controls.KEYS.MOVE :
this.state = Controls.STATES.MOVE;
event.preventDefault();
break;
case Controls.KEYS.ORBIT :
this.state = Controls.STATES.ORBIT;
event.preventDefault();
break;
}
};
onMouseUp = event => {
if (this.state === Controls.STATES.NONE) return;
switch (event.button) {
case Controls.KEYS.MOVE :
if (this.state === Controls.STATES.MOVE) this.state = Controls.STATES.NONE;
break;
case Controls.KEYS.ORBIT :
if (this.state === Controls.STATES.ORBIT) this.state = Controls.STATES.NONE;
break;
}
};
onTouchDown = event => {
if (event.pointerType === "mouse") return;
$(":focus").blur();
this.touchStart.x = this.targetPosition.x;
this.touchStart.y = this.targetPosition.z;
this.state = Controls.STATES.MOVE;
};
onTouchMove = event => {
if (event.pointerType === "mouse") return;
if (this.state !== Controls.STATES.MOVE) return;
this.touchDelta.x = event.deltaX;
this.touchDelta.y = event.deltaY;
if (this.touchDelta.x !== 0 || this.touchDelta.y !== 0) {
this.touchDelta.rotateAround(Vector2_ZERO, -this.direction);
this.targetPosition.x = this.touchStart.x - (this.touchDelta.x * this.distance / this.element.clientHeight * this.settings.move.speed);
this.targetPosition.z = this.touchStart.y - (this.touchDelta.y * this.distance / this.element.clientHeight * this.settings.move.speed);
}
};
onTouchUp = event => {
if (event.pointerType === "mouse") return;
this.state = Controls.STATES.NONE;
};
onTouchTiltDown = event => {
this.touchTiltStart = this.targetAngle;
this.state = Controls.STATES.ORBIT;
};
onTouchTiltMove = event => {
if (this.state !== Controls.STATES.ORBIT) return;
this.targetAngle = this.touchTiltStart - (event.deltaY / this.element.clientHeight * Math.PI);
};
onTouchTiltUp = event => {
this.state = Controls.STATES.NONE;
};
onTouchRotateDown = event => {
this.lastTouchRotation = event.rotation;
this.state = Controls.STATES.ORBIT;
};
onTouchRotateMove = event => {
if (this.state !== Controls.STATES.ORBIT) return;
let delta = event.rotation - this.lastTouchRotation;
this.lastTouchRotation = event.rotation;
if (delta > 180) delta -= 360;
if (delta < -180) delta += 360;
this.targetDirection += (delta * (Math.PI / 180)) * 1.4;
};
onTouchRotateUp = event => {
this.state = Controls.STATES.NONE;
};
onTouchZoomDown = event => {
this.touchZoomStart = this.targetDistance;
};
onTouchZoomMove = event => {
this.targetDistance = this.touchZoomStart / event.scale;
if (this.targetDistance < this.settings.zoom.min) this.targetDistance = this.settings.zoom.min;
if (this.targetDistance > this.settings.zoom.max) this.targetDistance = this.settings.zoom.max;
};
onKeyDown = event => {
this.keyStates[event.keyCode] = true;
};
onKeyUp = event => {
this.keyStates[event.keyCode] = false;
};
onInfoClick = event => {
$(document).trigger({
type: 'bluemap-info-click',
pos: event.center
});
}
}

View File

@ -1,59 +0,0 @@
/*
* 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.
*/
export default class Tile {
isLoading = false;
disposed = false;
model = null;
constructor(scene, x, z) {
this.scene = scene;
this.x = x;
this.z = z;
}
setModel(model) {
this.disposeModel();
if (model) {
this.model = model;
this.scene.add(model);
//console.log('Added tile:', this.x, this.z);
}
}
disposeModel() {
this.disposed = true;
if (this.model) {
this.scene.remove(this.model);
this.model.geometry.dispose();
delete this.model;
//console.log('Removed tile:', this.x, this.z);
}
}
}

View File

@ -1,198 +0,0 @@
/*
* 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 { Vector2 } from 'three';
import Tile from './Tile.js';
import { hashTile } from './utils.js';
export default class TileManager {
constructor(blueMap, viewDistance, tileLoader, scene, tileSize, tileOffset, position) {
this.blueMap = blueMap;
this.tileSize = new Vector2(tileSize.x, tileSize.z);
this.tileOffset = new Vector2(tileOffset.x, tileOffset.z);
this.setViewDistance(viewDistance);
this.tileLoader = tileLoader;
this.scene = scene;
this.tile = new Vector2(0, 0);
this.tile.set(position.x, position.z).divide(this.tileSize).floor();
this.lastTile = this.tile.clone();
this.closed = false;
this.currentlyLoading = 0;
this.updateTimeout = null;
this.tiles = {};
}
setViewDistance(viewDistance){
this.viewDistanceX = viewDistance / this.tileSize.x;
this.viewDistanceZ = viewDistance / this.tileSize.y;
}
setPosition(center) {
this.tile.set(center.x, center.z).sub(this.tileOffset).divide(this.tileSize).floor();
if (!this.tile.equals(this.lastTile) && !this.closed) {
this.update();
this.lastTile.copy(this.tile);
}
}
update() {
if (this.closed) return;
// free a loader so if there was an error loading a tile we don't get stuck forever with the blocked loading process
this.currentlyLoading--;
if (this.currentlyLoading < 0) this.currentlyLoading = 0;
this.removeFarTiles();
this.loadCloseTiles();
}
removeFarTiles() {
let keys = Object.keys(this.tiles);
for (let i = 0; i < keys.length; i++) {
if (!this.tiles.hasOwnProperty(keys[i])) continue;
let tile = this.tiles[keys[i]];
let vdx = this.viewDistanceX;
let vdz = this.viewDistanceZ;
if (
tile.x + vdx < this.tile.x ||
tile.x - vdx > this.tile.x ||
tile.z + vdz < this.tile.y ||
tile.z - vdz > this.tile.y
) {
tile.disposeModel();
delete this.tiles[keys[i]];
this.blueMap.updateFrame = true;
}
}
}
removeAllTiles() {
let keys = Object.keys(this.tiles);
for (let i = 0; i < keys.length; i++) {
if (!this.tiles.hasOwnProperty(keys[i])) continue;
let tile = this.tiles[keys[i]];
tile.disposeModel();
delete this.tiles[keys[i]];
}
this.blueMap.updateFrame = true;
}
close() {
this.closed = true;
this.removeAllTiles();
}
loadCloseTiles() {
if (this.closed) return;
if (this.currentlyLoading < 8) {
if (!this.loadNextTile()) return;
}
if (this.updateTimeout) clearTimeout(this.updateTimeout);
this.updateTimeout = setTimeout(() => this.loadCloseTiles(), 0);
}
loadNextTile() {
let x = 0;
let z = 0;
let d = 1;
let m = 1;
while (m < Math.max(this.viewDistanceX, this.viewDistanceZ) * 2 + 1) {
while (2 * x * d < m) {
if (this.tryLoadTile(this.tile.x + x, this.tile.y + z)) return true;
x = x + d;
}
while (2 * z * d < m) {
if (this.tryLoadTile(this.tile.x + x, this.tile.y + z)) return true;
z = z + d;
}
d = -1 * d;
m = m + 1;
}
return false;
}
tryLoadTile(x, z) {
if (this.closed) return false;
if (Math.abs(x - this.tile.x) > this.viewDistanceX) return false;
if (Math.abs(z - this.tile.z) > this.viewDistanceZ) return false;
let tileHash = hashTile(x, z);
let tile = this.tiles[tileHash];
if (tile !== undefined) return false;
tile = new Tile(this.scene, x, z);
tile.isLoading = true;
this.currentlyLoading++;
this.tiles[tileHash] = tile;
this.tileLoader.call(this.blueMap, x, z)
.then(model => {
tile.isLoading = false;
if (tile.disposed || this.closed) {
model.geometry.dispose();
tile.disposeModel();
delete this.tiles[tileHash];
return;
}
this.tiles[tileHash] = tile;
tile.setModel(model);
this.blueMap.updateFrame = true;
this.currentlyLoading--;
if (this.currentlyLoading < 0) this.currentlyLoading = 0;
}).catch(error => {
tile.isLoading = false;
tile.disposeModel();
this.currentlyLoading--;
//console.log("Failed to load tile: ", x, z);
});
return true;
}
}

View File

@ -1,190 +0,0 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
import {
Matrix4,
Object3D,
Vector3
} from "three";
var CSS2DObject = function ( element ) {
Object3D.call( this );
this.element = element;
this.element.style.position = 'absolute';
this.addEventListener( 'removed', function () {
this.traverse( function ( object ) {
if ( object.element instanceof Element && object.element.parentNode !== null ) {
object.element.parentNode.removeChild( object.element );
}
} );
} );
};
CSS2DObject.prototype = Object.create( Object3D.prototype );
CSS2DObject.prototype.constructor = CSS2DObject;
//
var CSS2DRenderer = function () {
var _this = this;
var _width, _height;
var _widthHalf, _heightHalf;
var vector = new Vector3();
var viewMatrix = new Matrix4();
var viewProjectionMatrix = new Matrix4();
var cache = {
objects: new WeakMap()
};
var domElement = document.createElement( 'div' );
domElement.style.overflow = 'hidden';
this.domElement = domElement;
this.getSize = function () {
return {
width: _width,
height: _height
};
};
this.setSize = function ( width, height ) {
_width = width;
_height = height;
_widthHalf = _width / 2;
_heightHalf = _height / 2;
domElement.style.width = width + 'px';
domElement.style.height = height + 'px';
};
var renderObject = function ( object, scene, camera ) {
if ( object instanceof CSS2DObject ) {
object.onBeforeRender( _this, scene, camera );
vector.setFromMatrixPosition( object.matrixWorld );
vector.applyMatrix4( viewProjectionMatrix );
var element = object.element;
var style = 'translate(-50%,-50%) translate(' + ( vector.x * _widthHalf + _widthHalf ) + 'px,' + ( - vector.y * _heightHalf + _heightHalf ) + 'px)';
element.style.WebkitTransform = style;
element.style.MozTransform = style;
element.style.oTransform = style;
element.style.transform = style;
element.style.display = ( object.visible && vector.z >= - 1 && vector.z <= 1 ) ? '' : 'none';
var objectData = {
distanceToCameraSquared: getDistanceToSquared( camera, object )
};
cache.objects.set( object, objectData );
if ( element.parentNode !== domElement ) {
domElement.appendChild( element );
}
object.onAfterRender( _this, scene, camera );
}
for ( var i = 0, l = object.children.length; i < l; i ++ ) {
renderObject( object.children[ i ], scene, camera );
}
};
var getDistanceToSquared = function () {
var a = new Vector3();
var b = new Vector3();
return function ( object1, object2 ) {
a.setFromMatrixPosition( object1.matrixWorld );
b.setFromMatrixPosition( object2.matrixWorld );
return a.distanceToSquared( b );
};
}();
var filterAndFlatten = function ( scene ) {
var result = [];
scene.traverse( function ( object ) {
if ( object instanceof CSS2DObject ) result.push( object );
} );
return result;
};
var zOrder = function ( scene ) {
var sorted = filterAndFlatten( scene ).sort( function ( a, b ) {
var distanceA = cache.objects.get( a ).distanceToCameraSquared;
var distanceB = cache.objects.get( b ).distanceToCameraSquared;
return distanceA - distanceB;
} );
var zMax = sorted.length;
for ( var i = 0, l = sorted.length; i < l; i ++ ) {
sorted[ i ].element.style.zIndex = zMax - i;
}
};
this.render = function ( scene, camera ) {
if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
if ( camera.parent === null ) camera.updateMatrixWorld();
viewMatrix.copy( camera.matrixWorldInverse );
viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, viewMatrix );
renderObject( scene, scene, camera );
zOrder( scene );
};
};
export { CSS2DObject, CSS2DRenderer };

View File

@ -1,205 +0,0 @@
import $ from 'jquery';
import {
Raycaster,
Vector2,
Vector3,
BoxBufferGeometry,
Mesh,
MeshBasicMaterial
} from 'three';
import {CSS2DObject} from './CSS2DRenderer';
import {pathFromCoords} from "../utils";
export default class HudInfo {
constructor(blueMap){
this.blueMap = blueMap;
let blockMarkerGeo = new BoxBufferGeometry( 1.01, 1.01, 1.01 );
blockMarkerGeo.translate(0.5, 0.5, 0.5);
this.blockMarker = new Mesh(blockMarkerGeo, new MeshBasicMaterial( {
color: 0xffffff,
opacity: 0.5,
depthWrite: false,
transparent: true,
} ));
this.rayPosition = new Vector2();
this.raycaster = new Raycaster();
this.element = $(`
<div class="hud-info"><div class="bubble" style="display: none">
<div class="content"></div>
</div></div>
`);
this.bubble = this.element.find(".bubble");
this.hudElement = new CSS2DObject(this.element[0]);
$(document).on('bluemap-info-click', this.onShowInfo);
$(window).on('mousedown wheel touchstart', this.onHideInfo);
}
showInfoBubble(content, x, y, z, onClose) {
if (this.onClose){
this.onClose();
this.onClose = undefined;
}
this.bubble.hide();
this.bubble.find(".content").html(content);
this.hudElement.position.set(x, y, z);
this.bubble.stop();
this.blueMap.hudScene.add(this.hudElement);
this.bubble.fadeIn(200);
this.onClose = onClose;
this.blueMap.updateFrame = true;
}
onShowInfo = event => {
this.rayPosition.x = ( event.pos.x / this.blueMap.element.offsetWidth ) * 2 - 1;
this.rayPosition.y = - ( event.pos.y / this.blueMap.element.offsetHeight ) * 2 + 1;
this.raycaster.setFromCamera(this.rayPosition, this.blueMap.camera);
//check markers first
let intersects = this.raycaster.intersectObjects( this.blueMap.shapeScene.children );
if (intersects.length !== 0){
if (this.blueMap.debugInfo){
console.debug("Tapped position data: ", intersects[0]);
}
try {
intersects[0].object.userData.marker.onClick(intersects[0].point);
} catch (ignore) {}
return;
}
//then show position info
let hiresData = true;
intersects = this.raycaster.intersectObjects( this.blueMap.hiresScene.children );
if (intersects.length === 0){
hiresData = false;
intersects = this.raycaster.intersectObjects( this.blueMap.lowresScene.children );
}
if (intersects.length > 0) {
let content = $("<div></div>");
if (this.blueMap.debugInfo){
console.debug("Tapped position data: ", intersects[0]);
}
//clicked position
let point = intersects[0].point;
let normal = intersects[0].face.normal;
let block = {
x: Math.floor(point.x - normal.x * 0.001),
y: Math.floor(point.y - normal.y * 0.001),
z: Math.floor(point.z - normal.z * 0.001),
};
if (hiresData) {
$(`
<div class="label">block:</div>
<div class="coords block">
<div class="coord"><span class="label">x</span><span class="value">${block.x}</span></div>
<div class="coord"><span class="label">y</span><span class="value">${block.y}</span></div>
<div class="coord"><span class="label">z</span><span class="value">${block.z}</span></div>
</div>
`).appendTo(content);
} else {
$(`
<div class="label">position:</div>
<div class="coords block">
<div class="coord"><span class="label">x</span><span class="value">${block.x}</span></div>
<div class="coord"><span class="label">z</span><span class="value">${block.z}</span></div>
</div>
`).appendTo(content);
}
//find light-data
if (hiresData) {
let vecIndex = intersects[0].face.a;
let attributes = intersects[0].object.geometry.attributes;
let sunlight = attributes.sunlight.array[vecIndex * attributes.sunlight.itemSize];
let blocklight = attributes.blocklight.array[vecIndex * attributes.blocklight.itemSize];
$(`
<div class="label" data-show="light">light:</div>
<div class="coords block">
<div class="coord"><span class="label">sun</span><span class="value">${sunlight}</span></div>
<div class="coord"><span class="label">block</span><span class="value">${blocklight}</span></div>
</div>
`).appendTo(content);
}
if (this.blueMap.debugInfo) {
//hires tile path
let hiresTileSize = this.blueMap.settings.maps[this.blueMap.map]['hires']['tileSize'];
hiresTileSize.y = hiresTileSize.z;
let hiresTileOffset = this.blueMap.settings.maps[this.blueMap.map]['hires']['translate'];
hiresTileOffset.y = hiresTileOffset.z;
let hiresTile = new Vector2(block.x, block.z).sub(hiresTileOffset).divide(hiresTileSize).floor();
let hrpath = this.blueMap.dataRoot + this.blueMap.map + '/hires/';
hrpath += pathFromCoords(hiresTile.x, hiresTile.y);
hrpath += '.json';
//lowres tile path
let lowresTileSize = this.blueMap.settings.maps[this.blueMap.map]['lowres']['tileSize'];
lowresTileSize.y = lowresTileSize.z;
let lowresTileOffset = this.blueMap.settings.maps[this.blueMap.map]['lowres']['translate'];
lowresTileOffset.y = lowresTileOffset.z;
let lowresTile = new Vector2(block.x, block.z).sub(lowresTileOffset).divide(lowresTileSize).floor();
let lrpath = this.blueMap.dataRoot + this.blueMap.map + '/lowres/';
lrpath += pathFromCoords(lowresTile.x, lowresTile.y);
lrpath += '.json';
//chunk
let chunkCoords = new Vector3(block.x, block.y, block.z).divide({x:16,y:16,z:16}).floor();
let chunk = `x:${chunkCoords.x}, y:${chunkCoords.y}, z:${chunkCoords.z}`;
//region
let regionCoords = new Vector2(block.x, block.z).divide({x:512,y:512}).floor();
let region = `r.${regionCoords.x}.${regionCoords.y}.mca`;
$(`
<div class="files">
<span class="value">${hrpath}</span><br>
<span class="value">${lrpath}</span><br>
<span class="value">chunk: ${chunk}</span><br>
<span class="value">region: ${region}</span>
</div>
`).appendTo(content);
}
//add block marker
if (hiresData){
this.blockMarker.position.set(block.x, block.y, block.z);
this.blueMap.shapeScene.add(this.blockMarker);
this.blockMarker.needsUpdate = true;
}
this.showInfoBubble(content.html(), block.x + 0.5, block.y + 1, block.z + 0.5);
}
};
onHideInfo = event => {
if (!this.bubble.is(':animated')) {
this.bubble.fadeOut(200, () => {
this.blueMap.hudScene.remove(this.hudElement);
if (this.onClose){
this.onClose();
this.onClose = undefined;
}
});
this.blueMap.shapeScene.remove(this.blockMarker);
this.blueMap.updateFrame = true;
}
};
};

View File

@ -1,39 +0,0 @@
import {Vector3} from "three";
export default class Marker {
constructor(blueMap, markerSet, markerData) {
this.blueMap = blueMap;
this.markerSet = markerSet;
this.type = markerData.type;
this.map = markerData.map;
this.position = new Vector3(markerData.position.x, markerData.position.y, markerData.position.z);
this.label = `<div class="marker-label">${markerData.label}</div>`;
this.link = markerData.link;
this.newTab = !!markerData.newTab;
this.visible = false;
this.minDistance = parseFloat(markerData.minDistance ? markerData.minDistance : 0);
this.minDistanceSquared = this.minDistance * this.minDistance;
this.maxDistance = parseFloat(markerData.maxDistance ? markerData.maxDistance : 100000);
this.maxDistanceSquared = this.maxDistance * this.maxDistance;
}
setVisible(visible) {
this.visible = visible && this.blueMap.map === this.map;
this.blueMap.updateFrame = true;
}
updateRenderObject(object, scene, camera){
if (this.visible) {
//update visiblity
let distanceSquared = this.position.distanceToSquared(camera.position);
object.visible = distanceSquared <= this.maxDistanceSquared && distanceSquared >= this.minDistanceSquared;
} else {
object.visible = false;
scene.remove(object);
}
}
}

View File

@ -1,133 +0,0 @@
import MarkerSet from "./MarkerSet";
import $ from "jquery";
import ToggleButton from "../ui/ToggleButton";
import Label from "../ui/Label";
import {cachePreventionNr} from "../utils";
import PlayerMarkerSet from "./PlayerMarkerSet";
export default class MarkerManager {
constructor(blueMap, ui) {
this.blueMap = blueMap;
this.ui = ui;
this.markerData = null;
this.liveData = null;
this.markerSets = [];
this.playerMarkerSet = null;
this.readyPromise =
Promise.all([
this.loadMarkerData()
.catch(ignore => {
if (this.blueMap.debugInfo) console.debug("Failed load markers:", ignore);
}),
this.checkLiveAPI()
.then(this.initializePlayerMarkers)
.catch(ignore => {
if (this.blueMap.debugInfo) console.debug("Failed load live-players:", ignore);
})
])
.then(this.loadMarkers)
.then(this.updatePlayerMarkerLoop);
$(document).on('bluemap-map-change', this.onBlueMapMapChange);
}
loadMarkerData() {
return new Promise((resolve, reject) => {
this.blueMap.fileLoader.load(this.blueMap.dataRoot + 'markers.json?' + cachePreventionNr(),
markerData => {
try {
this.markerData = JSON.parse(markerData);
resolve();
} catch (e){
reject(e);
}
},
xhr => {},
error => {
reject();
}
);
});
}
checkLiveAPI() {
return new Promise((resolve, reject) => {
this.blueMap.fileLoader.load(this.blueMap.liveApiRoot + 'players?' + cachePreventionNr(),
liveData => {
try {
this.liveData = JSON.parse(liveData);
resolve();
} catch (e){
reject(e);
}
},
xhr => {},
error => {
reject();
}
);
});
}
loadMarkers = () => {
if (this.markerData && this.markerData.markerSets) {
this.markerData.markerSets.forEach(setData => {
this.markerSets.push(new MarkerSet(this.blueMap, setData));
});
}
};
initializePlayerMarkers = () => {
if (this.liveData){
this.playerMarkerSet = new PlayerMarkerSet(this.blueMap);
this.markerSets.push(this.playerMarkerSet);
}
};
update(){
this.markerSets.forEach(markerSet => {
markerSet.update();
});
}
updatePlayerMarkerLoop = () => {
if (this.playerMarkerSet){
this.playerMarkerSet.updateLive();
}
setTimeout(this.updatePlayerMarkerLoop, 2000);
};
addMenuElements(menu){
let addedLabel = false;
this.markerSets.forEach(markerSet => {
if (markerSet.toggleable) {
if (!addedLabel){
menu.addElement(new Label("marker:"));
addedLabel = true;
}
let menuElement = new ToggleButton(markerSet.label, !markerSet.defaultHide, button => {
markerSet.visible = button.isSelected();
markerSet.update();
});
markerSet.visible = !markerSet.defaultHide;
markerSet.update();
menu.addElement(menuElement);
}
});
}
onBlueMapMapChange = async () => {
await this.readyPromise;
this.update();
};
}

View File

@ -1,40 +0,0 @@
import POIMarker from "./POIMarker";
import ShapeMarker from "./ShapeMarker";
export default class MarkerSet {
constructor(blueMap, setData) {
this.blueMap = blueMap;
this.id = setData.id;
this.label = setData.label ? this.escapeHTML(setData.label) : this.id;
this.toggleable = setData.toggleable !== undefined ? !!setData.toggleable : true;
this.defaultHide = !!setData.defaultHide;
this.marker = [];
this.visible = true;
if (Array.isArray(setData.marker)){
setData.marker.forEach(markerData => {
switch (markerData.type){
case 'poi':
this.marker.push(new POIMarker(this.blueMap, this, markerData));
break;
case 'shape':
this.marker.push(new ShapeMarker(this.blueMap, this, markerData));
break;
}
});
}
}
update() {
this.marker.forEach(marker => {
marker.setVisible(this.visible);
});
}
escapeHTML(text) {
return text.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
}

View File

@ -1,54 +0,0 @@
import $ from 'jquery';
import Marker from "./Marker";
import {CSS2DObject} from "./CSS2DRenderer";
import POI from "../../../assets/poi.svg";
export default class POIMarker extends Marker {
constructor(blueMap, markerSet, markerData) {
super(blueMap, markerSet, markerData);
this.icon = markerData.icon ? markerData.icon : POI;
this.iconAnchor = {
x: markerData.iconAnchor.x,
y: markerData.iconAnchor.y
};
}
setVisible(visible){
super.setVisible(visible);
if (!this.renderObject){
let iconElement = $(`<div class="marker-poi"><img src="${this.icon}" style="transform: translate(50%, 50%) translate(${-this.iconAnchor.x}px, ${-this.iconAnchor.y}px)"></div>`);
iconElement.find("img").click(this.onClick);
this.renderObject = new CSS2DObject(iconElement[0]);
this.renderObject.position.copy(this.position);
this.renderObject.onBeforeRender = (renderer, scene, camera) => this.updateRenderObject(this.renderObject, scene, camera);
}
if (this.visible) {
this.blueMap.hudScene.add(this.renderObject);
} else {
this.blueMap.hudScene.remove(this.renderObject);
}
}
onClick = () => {
if (this.label) {
this.setVisible(false);
this.blueMap.ui.hudInfo.showInfoBubble(this.label, this.position.x, this.position.y, this.position.z, () => {
this.setVisible(this.markerSet.visible);
});
}
if (this.link){
if (this.newTab){
window.open(this.link, '_blank');
} else {
location.href = this.link;
}
}
}
}

View File

@ -1,139 +0,0 @@
import $ from 'jquery';
import Marker from "./Marker";
import {CSS2DObject} from "./CSS2DRenderer";
import STEVE from "../../../assets/playerheads/steve.png";
export default class PlayerMarker extends Marker {
constructor(blueMap, markerSet, markerData, playerUuid, worldUuid) {
super(blueMap, markerSet, markerData);
this.online = false;
this.player = playerUuid;
this.world = worldUuid;
this.animationRunning = false;
this.lastFrame = -1;
this.follow = false;
}
setVisible(visible){
this.visible = visible && this.online && this.world === this.blueMap.settings.maps[this.blueMap.map].world;
this.blueMap.updateFrame = true;
if (!this.renderObject){
this.iconElement = $(`<div class="marker-player"><img src="assets/playerheads/${this.player}.png" onerror="this.onerror=null;this.src='${STEVE}';"><div class="nameplate">${this.label}</div></div>`);
this.iconElement.find("img").click(this.onClick);
$(window).on('mousedown touchstart', this.onUserInput);
this.renderObject = new CSS2DObject(this.iconElement[0]);
this.renderObject.position.copy(this.position);
this.renderObject.onBeforeRender = (renderer, scene, camera) => {
let distanceSquared = this.position.distanceToSquared(camera.position);
if (distanceSquared > 1000000) {
this.iconElement.addClass("distant");
} else {
this.iconElement.removeClass("distant");
}
this.updateRenderObject(this.renderObject, scene, camera);
};
}
if (this.visible) {
this.blueMap.hudScene.add(this.renderObject);
} else {
this.blueMap.hudScene.remove(this.renderObject);
if (this.follow) {
this.stopFollow();
}
}
}
updatePosition = () => {
if (this.renderObject && (!this.renderObject.position.equals(this.position) || this.worldChanged)) {
if (this.visible) {
if (!this.animationRunning) {
this.animationRunning = true;
requestAnimationFrame(this.moveAnimation);
}
} else {
this.renderObject.position.copy(this.position);
}
// try to find a map to follow player if he changes worlds
if (this.follow && this.worldChanged){
let found = false;
for (let id of this.blueMap.maps) {
let mapSettings = this.blueMap.settings.maps[id];
if (mapSettings.world === this.world) {
this.blueMap.changeMap(id);
found = true;
break;
}
}
if (!found){
this.stopFollow();
}
}
// still following? then update position
if (this.follow) {
this.blueMap.controls.targetPosition.copy(this.position);
}
}
};
moveAnimation = (time) => {
let delta = time - this.lastFrame;
if (this.lastFrame === -1){
delta = 20;
}
this.lastFrame = time;
if (this.renderObject && !this.renderObject.position.equals(this.position)) {
this.renderObject.position.x += (this.position.x - this.renderObject.position.x) * 0.01 * delta;
this.renderObject.position.y += (this.position.y - this.renderObject.position.y) * 0.01 * delta;
this.renderObject.position.z += (this.position.z - this.renderObject.position.z) * 0.01 * delta;
if (this.renderObject.position.distanceToSquared(this.position) < 0.001) {
this.renderObject.position.copy(this.position);
}
this.blueMap.updateFrame = true;
requestAnimationFrame(this.moveAnimation);
} else {
this.animationRunning = false;
this.lastFrame = -1;
}
};
onClick = () => {
this.startFollow();
};
onUserInput = e => {
if ((e.type !== "mousedown" || e.button === 0) && this.follow) {
this.stopFollow();
}
};
startFollow() {
this.follow = true;
this.iconElement.addClass("following");
this.blueMap.controls.targetPosition.copy(this.position);
}
stopFollow() {
this.follow = false;
this.iconElement.removeClass("following");
this.blueMap.controls.targetPosition.y = 0;
}
}

View File

@ -1,93 +0,0 @@
import POIMarker from "./POIMarker";
import ShapeMarker from "./ShapeMarker";
import {cachePreventionNr} from "../utils";
import PlayerMarker from "./PlayerMarker";
import {Vector3} from "three";
export default class PlayerMarkerSet {
constructor(blueMap) {
this.blueMap = blueMap;
this.id = "bluemap-live-players";
this.label = "players";
this.toggleable = true;
this.defaultHide = false;
this.marker = [];
this.markerMap = {};
this.visible = true;
}
update() {
this.marker.forEach(marker => {
marker.setVisible(this.visible);
});
}
async updateLive(){
await new Promise((resolve, reject) => {
this.blueMap.fileLoader.load(this.blueMap.liveApiRoot + 'players?' + cachePreventionNr(),
liveData => {
try {
liveData = JSON.parse(liveData);
resolve(liveData);
} catch (e){
reject(e);
}
},
xhr => {},
error => {
reject(error);
}
);
}).then((liveData) => {
this.updateWith(liveData)
}).catch(() => {
this.marker.forEach(marker => {
marker.online = false;
marker.setVisible(false);
});
});
}
updateWith(liveData){
this.marker.forEach(marker => {
marker.nowOnline = false;
marker.worldChanged = false;
});
for(let i = 0; i < liveData.players.length; i++){
let player = liveData.players[i];
let marker = this.markerMap[player.uuid];
if (!marker){
marker = new PlayerMarker(this.blueMap, this, {
type: "playermarker",
map: null,
position: player.position,
label: player.name,
link: null,
newTab: false
}, player.uuid, player.world);
this.markerMap[player.uuid] = marker;
this.marker.push(marker);
}
marker.nowOnline = true;
marker.position = new Vector3(player.position.x, player.position.y + 1.5, player.position.z);
if (marker.world !== player.world) {
marker.world = player.world;
marker.worldChanged = true;
}
marker.updatePosition();
}
this.marker.forEach(marker => {
if (marker.nowOnline !== marker.online || marker.worldChanged){
marker.online = marker.nowOnline;
marker.setVisible(this.visible);
}
});
}
}

View File

@ -1,112 +0,0 @@
import {
Vector2,
Shape,
MeshBasicMaterial,
Mesh,
Line,
LineBasicMaterial,
BufferGeometry,
ShapeBufferGeometry,
DoubleSide
} from 'three';
import Marker from "./Marker";
import $ from "jquery";
export default class ShapeMarker extends Marker {
constructor(blueMap, markerSet, markerData) {
super(blueMap, markerSet, markerData);
let points = [];
if (Array.isArray(markerData.shape)) {
markerData.shape.forEach(point => {
points.push(new Vector2(point.x, point.z));
});
}
this.height = markerData.height ? markerData.height : 128;
this.fillColor = this.prepareColor(markerData.fillColor);
this.borderColor = this.prepareColor(markerData.borderColor);
this.depthTest = !!markerData.depthTest;
//fill
let shape = new Shape(points);
let fillGeo = new ShapeBufferGeometry(shape, 1);
fillGeo.rotateX(Math.PI * 0.5);
fillGeo.translate(0, this.height + 0.01456, 0);
let fillMaterial = new MeshBasicMaterial({
color: this.fillColor.rgb,
opacity: this.fillColor.a,
transparent: true,
side: DoubleSide,
depthTest: this.depthTest,
});
let fill = new Mesh( fillGeo, fillMaterial );
//border
points.push(points[0]);
let lineGeo = new BufferGeometry().setFromPoints(points);
lineGeo.rotateX(Math.PI * 0.5);
lineGeo.translate(0, this.height + 0.01456, 0);
let lineMaterial = new LineBasicMaterial({
color: this.borderColor.rgb,
opacity: this.borderColor.a,
transparent: true,
depthTest: false,
});
let line = new Line( lineGeo, lineMaterial );
if (this.fillColor.a > 0 || this.borderColor.a <= 0) {
this.renderObject = fill;
fill.add(line);
} else {
this.renderObject = line;
}
this.renderObject.userData = {
marker: this,
};
}
setVisible(visible){
super.setVisible(visible);
if (this.visible) {
this.blueMap.shapeScene.add(this.renderObject);
$(document).on('bluemap-update-frame', this.onRender);
} else {
this.blueMap.shapeScene.remove(this.renderObject);
$(document).off('bluemap-update-frame', this.onRender);
}
}
onRender = () => {
this.updateRenderObject(this.renderObject, this.blueMap.shapeScene, this.blueMap.camera);
};
onClick = (clickPos) => {
if (this.label) {
this.blueMap.ui.hudInfo.showInfoBubble(this.label, clickPos.x, clickPos.y, clickPos.z);
}
if (this.link){
if (this.newTab){
window.open(this.link, '_blank');
} else {
location.href = this.link;
}
}
};
prepareColor(color){
if (color.r === undefined) color.r = 0;
if (color.g === undefined) color.g = 0;
if (color.b === undefined) color.b = 0;
if (color.a === undefined) color.a = 1;
color.rgb = (color.r << 16) + (color.g << 8) + (color.b);
return color;
}
}

View File

@ -1,86 +0,0 @@
/*
* 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 { ShaderChunk } from 'three';
const HIRES_FRAGMENT_SHADER = `
${ShaderChunk.logdepthbuf_pars_fragment}
uniform sampler2D texture;
uniform float sunlightStrength;
uniform float ambientLight;
uniform bool mobSpawnOverlay;
varying vec3 vPosition;
varying vec3 vWorldPosition;
varying vec3 vNormal;
varying vec2 vUv;
varying vec3 vColor;
varying float vAo;
varying float vSunlight;
varying float vBlocklight;
vec4 lerp(vec4 v1, vec4 v2, float amount){
return v1 * (1.0 - amount) + v2 * amount;
}
vec3 lerp(vec3 v1, vec3 v2, float amount){
return v1 * (1.0 - amount) + v2 * amount;
}
bool mobSpawnColor() {
if (vBlocklight < 7.1 && vNormal.y > 0.8){
float cross1 = vUv.x - vUv.y;
float cross2 = vUv.x - (1.0 - vUv.y);
return cross1 < 0.05 && cross1 > -0.05 || cross2 < 0.05 && cross2 > -0.05;
}
return false;
}
void main() {
vec4 color = texture2D(texture, vUv);
if (color.a == 0.0) discard;
//apply vertex-color
color.rgb *= vColor;
//mob spawn overlay
if (mobSpawnOverlay && mobSpawnColor()){
color.rgb = lerp(vec3(1.0, 0.0, 0.0), color.rgb, 0.25);
}
//apply ao
color.rgb *= vAo;
//apply light
float light = max(vSunlight * sunlightStrength, vBlocklight);
color.rgb *= max(light / 15.0, ambientLight);
gl_FragColor = color;
${ShaderChunk.logdepthbuf_fragment}
}
`;
export default HIRES_FRAGMENT_SHADER;

View File

@ -1,64 +0,0 @@
/*
* 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 { ShaderChunk } from 'three';
const HIRES_VERTEX_SHADER = `
#define EPSILON 1e-6
${ShaderChunk.logdepthbuf_pars_vertex}
attribute float ao;
attribute float sunlight;
attribute float blocklight;
varying vec3 vPosition;
varying vec3 vWorldPosition;
varying vec3 vNormal;
varying vec2 vUv;
varying vec3 vColor;
varying float vAo;
varying float vSunlight;
varying float vBlocklight;
void main() {
vPosition = position;
vWorldPosition = (vec4(position, 1) * modelMatrix).xyz;
vNormal = normal;
vUv = uv;
vColor = color;
vAo = ao;
vSunlight = sunlight;
vBlocklight = blocklight;
gl_Position =
projectionMatrix *
viewMatrix *
modelMatrix *
vec4(position, 1);
${ShaderChunk.logdepthbuf_vertex}
}
`;
export default HIRES_VERTEX_SHADER;

View File

@ -1,52 +0,0 @@
/*
* 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 { ShaderChunk } from 'three';
const LOWRES_FRAGMENT_SHADER = `
${ShaderChunk.logdepthbuf_pars_fragment}
uniform float sunlightStrength;
uniform float ambientLight;
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUv;
varying vec3 vColor;
void main() {
vec4 color = vec4(vColor, 1.0);
float diff = sqrt(max(dot(vNormal, vec3(0.3637, 0.7274, 0.5819)), 0.0)) * 0.4 + 0.6;
color *= diff;
color *= max(sunlightStrength, ambientLight);
gl_FragColor = color;
${ShaderChunk.logdepthbuf_fragment}
}
`;
export default LOWRES_FRAGMENT_SHADER;

View File

@ -1,51 +0,0 @@
/*
* 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 { ShaderChunk } from 'three';
const LOWRES_VERTEX_SHADER = `
#define EPSILON 1e-6
${ShaderChunk.logdepthbuf_pars_vertex}
varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUv;
varying vec3 vColor;
void main() {
vPosition = position;
vNormal = normal;
vUv = uv;
vColor = color;
gl_Position =
projectionMatrix *
modelViewMatrix *
vec4(position, 1);
${ShaderChunk.logdepthbuf_vertex}
}
`;
export default LOWRES_VERTEX_SHADER;

View File

@ -1,41 +0,0 @@
/*
* 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.
*/
const SKY_FRAGMENT_SHADER = `
uniform float sunlightStrength;
uniform float ambientLight;
uniform vec3 skyColor;
varying vec3 vPosition;
void main() {
vec4 color = vec4(skyColor * max(sunlightStrength, ambientLight), 1.0);
color.rgb *= (clamp(vPosition.y, -0.02, 0.02) + 0.02) * 25.0;
gl_FragColor = color;
}
`;
export default SKY_FRAGMENT_SHADER;

View File

@ -1,39 +0,0 @@
/*
* 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.
*/
const SKY_VERTEX_SHADER = `
varying vec3 vPosition;
void main() {
vPosition = position;
gl_Position =
projectionMatrix *
modelViewMatrix *
vec4(position, 1);
}
`;
export default SKY_VERTEX_SHADER;

View File

@ -1,63 +0,0 @@
/*
* 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 $ from 'jquery';
import Element from './Element.js';
export default class Button extends Element {
constructor(label, onClick, icon){
super();
this.label = label;
this.onClickListener = onClick;
this.icon = icon;
}
createElement() {
let element = super.createElement();
element.addClass("button");
element.click(this.onClickEvent);
if (this.label !== undefined) {
$(`<div class="label">${this.label}</div>`).appendTo(element);
}
if (this.icon !== undefined){
element.addClass("icon");
$(`<img src="${this.icon}" />`).appendTo(element);
}
return element;
}
onClickEvent = () => {
if (this.onClickListener !== undefined && this.onClickListener !== null) {
this.onClickListener(this);
}
}
}

View File

@ -1,57 +0,0 @@
/*
* 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 $ from 'jquery';
import Button from './Button.js';
import COMPASS from '../../../assets/compass.svg';
export default class Compass extends Button {
constructor(blueMap) {
super(undefined, undefined, COMPASS);
this.blueMap = blueMap;
$(document).on('bluemap-update-frame', this.onBlueMapUpdateFrame);
}
createElement(){
let element = super.createElement();
element.click(this.onClick);
return element;
}
onBlueMapUpdateFrame = () => {
this.elements.forEach(element => {
element.find("img").css('transform', `rotate(${this.blueMap.controls.direction}rad)`);
});
};
onClick = () => {
this.blueMap.controls.targetDirection = 0;
this.blueMap.controls.direction = this.blueMap.controls.direction % (Math.PI * 2);
if (this.blueMap.controls.direction < -Math.PI) this.blueMap.controls.direction += Math.PI * 2;
if (this.blueMap.controls.direction > Math.PI) this.blueMap.controls.direction -= Math.PI * 2;
};
}

View File

@ -1,130 +0,0 @@
/*
* 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 $ from 'jquery';
import Element from './Element.js';
export default class Dropdown extends Element {
constructor(onChange, minWidth) {
super();
this.minWidth = minWidth;
this.value = null;
this.options = [];
this.onChange = onChange;
$(window).on('click', this.closeAll);
}
addOption(value, label, select) {
this.options.push({
value: value,
label: label,
select: select
});
if (this.value === null || select){
this.select(value);
}
}
createElement(){
let element = super.createElement();
element.addClass("dropdown");
let headerElement = $('<div class="header"></div>').appendTo(element);
let selectElement = $('<div class="select" style="display: none"></div>').appendTo(element);
headerElement.click(this.toggleEvent(element));
if (this.minWidth !== undefined){
this.element.addClass("sized");
this.element.css("min-width", this.minWidth);
}
this.options.forEach(option => {
let optionElement = $(`<div class="ui-element option" data-value="${option.value}">${option.label}</div>`).appendTo(selectElement);
optionElement.on('click', this.selectButtonEvent(option.value, optionElement));
if (this.value === option.value){
optionElement.addClass('selected');
headerElement.html('');
headerElement.append(optionElement.clone().off());
}
});
return element;
}
toggleEvent = element => event => {
let select = element.find(".select");
let open = select.css("display") !== "none";
this.closeAll();
if (!open) {
select.stop(true).slideDown(200);
element.addClass("open");
event.stopPropagation();
}
};
closeAll = () => {
this.elements.forEach(element => {
element.removeClass("open");
element.find(".select:not(:hidden)").stop(true).slideUp(200);
});
};
select = value => {
this.value = value;
this.elements.forEach(element => {
let selectElement = element.find(".select");
selectElement.find('.selected').removeClass('selected');
let option = selectElement.find(`.option[data-value='${value}']`);
option.addClass('selected');
let headerElement = element.find(".header");
headerElement.html('');
headerElement.append(option.clone().off());
});
};
selectButtonEvent = (value, option) => event => {
this.select(value);
//close
this.closeAll();
if (event !== undefined) event.stopPropagation();
if (this.onChange !== undefined && this.onChange !== null){
this.onChange(this.value, this);
}
};
}

View File

@ -1,39 +0,0 @@
/*
* 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 $ from 'jquery';
export default class Element {
constructor() {
this.elements = [];
}
createElement() {
let newElement = $('<div class="ui-element"></div>');
this.elements.push(newElement);
return newElement;
}
}

View File

@ -1,42 +0,0 @@
/*
* 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 Element from './Element.js';
export default class Label extends Element {
constructor(label){
super();
this.label = label;
}
createElement() {
let element = super.createElement();
element.addClass("label");
element.html(this.label);
return element;
}
}

View File

@ -1,61 +0,0 @@
/*
* 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 $ from 'jquery';
import Dropdown from "./Dropdown";
export default class MapSelection extends Dropdown {
constructor(bluemap) {
super(undefined);
super.onChange = this.onChangeMap;
this.bluemap = bluemap;
//add maps
const maps = this.bluemap.settings.maps;
for (let mapId of this.bluemap.maps) {
const map = maps[mapId];
if (!map.enabled) continue;
this.addOption(mapId, map.name);
}
$(document).on('bluemap-map-change', this.onBlueMapMapChange);
}
createElement() {
let element = super.createElement();
element.addClass("map-selection");
return element;
}
onChangeMap = value => {
this.bluemap.changeMap(value);
};
onBlueMapMapChange = () => {
this.select(this.bluemap.map);
};
}

View File

@ -1,89 +0,0 @@
/*
* 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 $ from 'jquery';
import Element from './Element.js';
import Separator from "./Separator";
export default class Menu {
constructor(){
this.element = $('<div class="menu closed"><h1>Menu</h1></div>');
this.content = $('<div class="content"></div>').appendTo(this.element);
this.closeButton = $('<div class="close-button"></div>').appendTo(this.element);
this.children = [];
this.closeButton.click(this.close);
}
addElement(element){
this.children.push(element);
}
update() {
this.content.html("");
this.children.forEach(child => {
this.content.append(child.createElement());
});
$(`<div class="footer-separator"></div>`).appendTo(this.content);
$(`
<div class="ui-element footer">
<h1>BlueMap</h1>
<p>
Visit BlueMap on <a href="https://github.com/BlueMap-Minecraft">GitHub</a> and <a href="https://discord.gg/zmkyJa3">Discord</a>!
</p>
<h2>Controls</h2>
<p>
<kbd>leftclick and drag</kbd> or <kbd>arrow-keys</kbd> to navigate<br>
<kbd>rightclick and drag</kbd> to rotate your view<br>
<kbd>scroll</kbd> to zoom in and out
</p>
</div>
`).appendTo(this.content);
}
isOpen = () => {
return !this.element.hasClass('closed');
};
toggleOpen = () => {
this.element.toggleClass('closed');
};
open = () => {
this.element.removeClass('closed');
this.element.trigger('menu-open');
};
close = () => {
this.element.addClass('closed');
this.element.trigger('menu-close');
};
}

View File

@ -1,57 +0,0 @@
/*
* 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 $ from 'jquery';
import ToggleButton from './ToggleButton.js';
import BURGER from '../../../assets/burger.svg';
export default class MenuButton extends ToggleButton {
constructor(menu) {
super(undefined, false, undefined, BURGER);
this.menu = menu;
this.menu.element.on('menu-close menu-open', this.updateMenuState);
}
createElement(){
let element = super.createElement();
element.click(this.onMenuClick);
return element;
}
updateMenuState = () => {
this.selected = this.menu.isOpen();
this.update();
};
onMenuClick = () => {
if (this.selected){
this.menu.open();
} else {
this.menu.close();
}
};
}

View File

@ -1,69 +0,0 @@
/*
* 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 $ from 'jquery';
import Element from "./Element";
export default class Position extends Element {
constructor(blueMap, axis) {
super();
this.blueMap = blueMap;
this.axis = axis;
$(document).on('bluemap-update-frame', this.update);
}
createElement(){
let element = super.createElement();
element.addClass("position");
element.attr("data-axis", this.axis);
let inputElement = $('<input type="number" value="0" />').appendTo(element);
inputElement.on('input', this.onInput);
inputElement.on('keydown', this.onKeyDown);
return element;
}
onInput = event => {
const value = Number(event.target.value);
if (!isNaN(value)) {
this.blueMap.controls.targetPosition[this.axis] = value;
this.update();
}
};
onKeyDown = event => {
event.stopPropagation();
};
update = () => {
const val = Math.floor(this.blueMap.controls.targetPosition[this.axis]);
this.elements.forEach(element => {
element.find("input").val(val);
});
};
}

View File

@ -1,58 +0,0 @@
/*
* 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 Element from './Element.js';
export default class Separator extends Element {
constructor(greedy = false){
super();
this.greedy = greedy;
}
createElement() {
let element = super.createElement();
element.addClass("separator");
if (this.greedy) element.addClass("greedy");
return element;
}
isGreedy(){
return this.greedy;
}
setGreedy(greedy){
this.greedy = greedy;
this.elements.forEach(element => {
if (this.greedy) {
element.addClass("greedy");
} else {
element.removeClass("greedy");
}
});
}
}

View File

@ -1,86 +0,0 @@
/*
* 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 $ from 'jquery';
import Element from './Element.js';
export default class Slider extends Element {
constructor(min = 0, max = 1, step = 0.01, value, onChange, minWidth){
super();
this.min = min;
this.max = max;
this.step = step;
if (value === undefined) value = min;
this.value = value;
this.onChangeListener = onChange;
this.minWidth = minWidth;
}
createElement() {
let element = super.createElement();
element.addClass("slider");
if (this.minWidth !== undefined){
element.addClass("sized");
element.css("min-width", this.minWidth);
}
let slider = $(`<input type="range" min="${this.min}" max="${this.max}" step="${this.step}" value="${this.value}">`).appendTo(element);
slider.on('input change', this.onChangeEvent(slider));
$(`<div class="label">-</div>`).appendTo(element);
this.update();
return element;
}
getValue() {
return this.value;
}
update(){
this.elements.forEach(element => {
let label = element.find(".label");
let slider = element.find("input");
slider.val(this.value);
label.html(Math.round(this.value * 100) / 100);
});
}
onChangeEvent = slider => () => {
this.value = slider.val();
this.update();
if (this.onChangeListener !== undefined && this.onChangeListener !== null) {
this.onChangeListener(this);
}
}
}

View File

@ -1,74 +0,0 @@
/*
* 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 $ from 'jquery';
import Button from './Button.js';
export default class ToggleButton extends Button {
constructor(label, selected, onChange, icon){
super(label, undefined, icon);
this.selected = selected;
this.onChangeListener = onChange;
}
createElement() {
let element = super.createElement();
element.addClass("toggle-button");
if (this.selected) element.addClass("selected");
$('<div class="switch"></div>').appendTo(element);
element.click(this.onClick);
return element;
}
isSelected(){
return this.selected;
}
toggle(){
this.selected = !this.selected;
this.update();
}
update(){
this.elements.forEach(element => {
if (this.selected)
element.addClass("selected");
else
element.removeClass("selected");
});
}
onClick = () => {
this.toggle();
if (this.onChangeListener !== undefined && this.onChangeListener !== null){
this.onChangeListener(this);
}
};
}

View File

@ -1,55 +0,0 @@
/*
* 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 $ from 'jquery';
import Element from './Element.js';
export default class Toolbar {
constructor(){
this.element = $('<div class="toolbar"></div>');
this.children = [];
}
addElement(element, hideOnMobile = false){
this.children.push({
element: element,
hideOnMobile: hideOnMobile
});
}
update() {
this.element.html("");
this.children.forEach(child => {
let element = child.element.createElement();
element.appendTo(this.element);
if (child.hideOnMobile){
element.addClass("mobile-hide");
}
});
}
}

View File

@ -1,143 +0,0 @@
/*
* 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 $ from 'jquery';
import Toolbar from './Toolbar.js';
import Menu from './Menu.js';
import Dropdown from "./Dropdown";
import Separator from "./Separator";
import Label from "./Label";
import MenuButton from './MenuButton.js';
import Compass from "./Compass";
import Position from "./Position";
import Button from "./Button";
import Slider from "./Slider";
import ToggleButton from "./ToggleButton";
import MapSelection from "./MapSeletion";
import NIGHT from '../../../assets/night.svg';
import HudInfo from "../hud/HudInfo";
import MarkerManager from "../hud/MarkerManager";
import {cachePreventionNr} from "../utils";
export default class UI {
constructor(blueMap) {
this.blueMap = blueMap;
this.element = $('<div class="ui"></div>').appendTo(this.blueMap.element);
this.menu = new Menu();
this.menu.element.appendTo(this.element);
this.hud = $('<div class="hud"></div>').appendTo(this.element);
this.toolbar = new Toolbar();
this.toolbar.element.appendTo(this.hud);
//modules
this.hudInfo = new HudInfo(this.blueMap);
this.markers = new MarkerManager(this.blueMap, this);
}
async load() {
//elements
let menuButton = new MenuButton(this.menu);
let mapSelect = new MapSelection(this.blueMap);
let nightButton = new ToggleButton("night", blueMap.targetSunLightStrength < 1, button => {
this.blueMap.targetSunLightStrength = button.isSelected() ? 0.1 : 1;
}, NIGHT);
let posX = new Position(this.blueMap, 'x');
let posZ = new Position(this.blueMap, 'z');
let compass = new Compass(this.blueMap);
let mobSpawnOverlay = new ToggleButton("mob-spawn (experimental)", blueMap.mobSpawnOverlay.value, button => {
this.blueMap.mobSpawnOverlay.value = button.isSelected();
this.blueMap.updateFrame = true;
});
let quality = new Dropdown(value => {
this.blueMap.quality = parseFloat(value);
this.blueMap.handleContainerResize();
});
quality.addOption("2", "high", this.blueMap.quality === 2);
quality.addOption("1", "normal", this.blueMap.quality === 1);
quality.addOption("0.5", "low", this.blueMap.quality === 0.5);
let hiresSlider = new Slider(32, 480, 1, this.blueMap.hiresViewDistance, v => {
this.blueMap.hiresViewDistance = v.getValue();
this.blueMap.hiresTileManager.setViewDistance(this.blueMap.hiresViewDistance);
this.blueMap.hiresTileManager.update();
});
let lowresSlider = new Slider(480, 6400, 1, this.blueMap.lowresViewDistance, v => {
this.blueMap.lowresViewDistance = v.getValue();
this.blueMap.lowresTileManager.setViewDistance(this.blueMap.lowresViewDistance);
this.blueMap.lowresTileManager.update();
});
let extendedZoom = new ToggleButton("extended zoom", this.blueMap.controls.settings.zoom.max > 2000, button => {
this.blueMap.controls.settings.zoom.max = button.isSelected() ? 8000 : 2000;
this.blueMap.controls.targetDistance = Math.min(this.blueMap.controls.targetDistance, this.blueMap.controls.settings.zoom.max);
});
let debugInfo = new ToggleButton("debug-info", this.blueMap.debugInfo, button => {
this.blueMap.debugInfo = button.isSelected();
});
let clearCache = new Button("clear tile cache", button => {
this.blueMap.cacheSuffix = cachePreventionNr();
this.blueMap.reloadMap();
});
//toolbar
this.toolbar.addElement(menuButton);
this.toolbar.addElement(mapSelect);
this.toolbar.addElement(new Separator(), true);
this.toolbar.addElement(nightButton, true);
this.toolbar.addElement(new Separator(true));
this.toolbar.addElement(posX);
this.toolbar.addElement(posZ);
this.toolbar.addElement(compass);
this.toolbar.update();
//menu
this.menu.addElement(nightButton);
//this.menu.addElement(mobSpawnOverlay);
await this.markers.readyPromise;
this.markers.addMenuElements(this.menu);
this.menu.addElement(new Separator());
this.menu.addElement(new Label('render quality:'));
this.menu.addElement(quality);
this.menu.addElement(new Label('hires render-distance (blocks):'));
this.menu.addElement(hiresSlider);
this.menu.addElement(new Label('lowres render-distance (blocks):'));
this.menu.addElement(lowresSlider);
this.menu.addElement(extendedZoom);
this.menu.addElement(new Separator());
this.menu.addElement(clearCache);
this.menu.addElement(debugInfo);
this.menu.update();
}
}

View File

@ -1,109 +0,0 @@
/*
* 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 { Vector2, Vector3 } from 'three';
export const cachePreventionNr = () => {
return Math.floor(Math.random() * 100000000);
};
export const stringToImage = string => {
let image = document.createElementNS('http://www.w3.org/1999/xhtml', 'img');
image.src = string;
return image;
};
export const pathFromCoords = (x, z) => {
let path = 'x';
path += splitNumberToPath(x);
path += 'z';
path += splitNumberToPath(z);
path = path.substring(0, path.length - 1);
return path;
};
export const splitNumberToPath = num => {
let path = '';
if (num < 0) {
num = -num;
path += '-';
}
let s = parseInt(num).toString();
for (let i = 0; i < s.length; i++) {
path += s.charAt(i) + '/';
}
return path;
};
export const hashTile = (x, z) => `x${x}z${z}`;
/**
* Adapted from https://www.w3schools.com/js/js_cookies.asp
*/
export const setCookie = (key, value, days = 360) => {
value = JSON.stringify(value);
let expireDate = new Date();
expireDate.setTime(expireDate.getTime() + days * 24 * 60 * 60 * 1000);
document.cookie = key + "=" + value + ";" + "expires=" + expireDate.toUTCString();
};
/**
* Adapted from https://www.w3schools.com/js/js_cookies.asp
*/
export const getCookie = key => {
let cookieString = decodeURIComponent(document.cookie);
let cookies = cookieString.split(';');
for(let i = 0; i < cookies.length; i++) {
let cookie = cookies[i];
while (cookie.charAt(0) === ' ') {
cookie = cookie.substring(1);
}
if (cookie.indexOf(key + "=") === 0) {
let value = cookie.substring(key.length + 1, cookie.length);
try {
value = JSON.parse(value);
} catch (e) {}
return value;
}
}
return undefined;
};
export const Vector2_ZERO = new Vector2(0, 0);
export const Vector3_ZERO = new Vector3(0, 0, 0);

View File

@ -1,8 +0,0 @@
import $ from 'jquery';
import BlueMap from './libs/BlueMap.js';
import '../style/style.scss';
$(document).ready(() => {
window.blueMap = new BlueMap($('#map-container')[0], 'data/');
});

View File

@ -1,18 +0,0 @@
// colors
$normal_fg: #333;
$normal_bg: #fff;
$label_fg: #666;
$hover_fg: $normal_fg;
$hover_bg: #aaa;
$active_fg: $normal_bg;
$active_bg: $normal_fg;
$line_color: #aaa;
// breakpoints
$super-small-max: 500px;
$small-max: 800px;
$middle-max: 1200px;

View File

@ -1,134 +0,0 @@
.bluemap-container .hud-info {
pointer-events: none;
}
.bluemap-container .hud-info .bubble {
transform: translate(0, calc(-50% - 0.5rem));
background-color: $normal_bg;
filter: drop-shadow(1px 1px 3px #0008);
white-space: nowrap;
.content {
position: relative;
> .label {
min-height: 0;
font-size: 0.8rem;
padding: 0.5rem 0.5rem 0 1rem;
line-height: 0.8rem;
color: $label_fg;
border-top: solid 1px $line_color;
&:first-child {
border-top: none;
}
}
> * {
padding: 0.5rem;
}
.coords {
display: flex;
justify-content: center;
> .coord {
margin: 0 0.2rem;
padding: 0 0.2rem;
border-radius: 0.2rem;
//background-color: #ccc;
> .label {
color: $label_fg;
margin-right: 0.2rem;
&::after {
content: ':';
}
}
}
}
> .files {
border-top: solid 1px $line_color;
font-size: 0.8rem;
line-height: 0.8rem;
color: $label_fg;
}
&::after {
content: '';
position: absolute;
bottom: calc(-1rem + 1px);
left: calc(50% - 0.5rem);
width: 0;
height: 0;
border: solid 0.5rem;
border-color: $normal_bg transparent transparent transparent;
}
}
}
.bluemap-container .marker-poi, .bluemap-container .marker-player {
pointer-events: none;
> * {
pointer-events: auto;
}
> img {
filter: drop-shadow(1px 1px 3px #0008);
}
}
.bluemap-container .marker-player {
img {
width: 32px;
height: 32px;
image-rendering: pixelated;
image-rendering: crisp-edges;
border: solid 2px transparent;
transition: all 0.3s;
}
.nameplate {
position: absolute;
left: 50%;
top: 0;
transform: translate(-50%, -110%);
background: rgba(50, 50, 50, 0.75);
padding: 0.2em 0.3em;
color: white;
transition: all 0.3s;
}
&.distant {
img {
width: 16px;
height: 16px;
border-width: 1px;
}
.nameplate {
opacity: 0;
}
}
&.following {
img {
border-color: white;
}
}
}

View File

@ -1,116 +0,0 @@
@import "constants";
html, body {
margin: 0;
padding: 0;
font-size: 16px;
line-height: 1rem;
font-family: Verdana,Helvetica,Arial,sans-serif;
color: $normal_fg;
background-color: $normal_bg;
@media (max-width: $small-max) {
font-size: 20px;
}
}
#map-container {
position: absolute;
width: 100%;
height: 100%;
}
.bluemap-container {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
> .map-canvas, .map-canvas-hud {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
> .map-canvas {
background-color: #000;
z-index: 0;
}
> .map-canvas-hud {
pointer-events: none;
z-index: 10;
> * {
pointer-events: auto;
}
}
> .ui {
display: flex;
align-items: stretch;
position: relative;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 100;
> * {
pointer-events: auto;
}
> .menu {
position: relative;
flex-shrink: 0;
z-index: 200;
filter: drop-shadow(1px 1px 3px #0008);
@media (max-width: $middle-max) {
position: absolute;
}
}
> .hud {
position: relative;
width: 100%;
pointer-events: none;
filter: drop-shadow(1px 1px 3px #0008);
> * {
pointer-events: auto;
}
}
}
}
@import "ui/ui";
@import "ui/element";
@import "ui/toolbar";
@import "ui/menu";
@import "ui/button";
@import "ui/slider";
@import "ui/togglebutton";
@import "ui/separator";
@import "ui/dropdown";
@import "ui/label";
@import "ui/position";
@import "modules/hudInfo";

View File

@ -1,39 +0,0 @@
.bluemap-container .ui .ui-element.button {
cursor: pointer;
user-select: none;
> .label {
margin: 0 0.5rem;
}
&.icon {
flex-grow: 0;
> .label {
display: none;
}
}
&:hover {
background-color: $hover_bg;
color: $hover_fg;
}
&:active {
background-color: $active_bg;
color: $active_fg;
> img {
filter: invert(1);
}
}
> img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}

View File

@ -1,86 +0,0 @@
.bluemap-container .ui .ui-element.dropdown {
padding: 0;
cursor: pointer;
overflow: visible;
user-select: none;
> .header {
height: 100%;
padding-right: 1rem;
&:hover {
background-color: $hover_bg;
color: $hover_fg;
&::after {
border-color: $hover_fg transparent transparent transparent;
}
}
> .ui-element {
pointer-events: none;
background-color: transparent;
}
&::after {
position: absolute;
top: calc(50% - 0.2rem);
right: 0.5rem;
content: "";
width: 0;
height: 0;
border: solid;
border-width: 0.4rem 0.25rem 0.4rem 0.25rem;
border-color: $normal_fg transparent transparent transparent;
}
}
&.open > .header {
background-color: $hover_bg;
color: $hover_fg;
&::after {
top: calc(50% - 0.6rem);
border-color: transparent transparent $hover_fg transparent;
}
}
> .select {
position: absolute;
top: 100%;
left: 0;
width: 100%;
overflow-x: hidden;
max-height: 10rem;
overflow-y: auto;
z-index: 110;
> .option {
background-color: $normal_bg;
color: $normal_fg;
&:hover {
background-color: $hover_bg;
color: $hover_fg;
}
&.selected {
background-color: $active_bg;
color: $active_fg;
}
}
}
.option {
padding: 0 0.5rem;
}
}

View File

@ -1,12 +0,0 @@
.bluemap-container .ui .ui-element {
position: relative;
min-width: 2rem;
min-height: 2rem;
line-height: 2rem;
padding: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

View File

@ -1,5 +0,0 @@
.bluemap-container .ui .ui-element.label {
color: $label_fg;
}

View File

@ -1,179 +0,0 @@
$menu-width: 375px;
.bluemap-container .ui .menu {
height: 100%;
width: $menu-width;
max-width: 100%;
background-color: $normal_bg;
color: $normal_fg;
overflow: hidden;
transition: width 0.2s;
&.closed {
width: 0;
}
@media (max-width: $menu-width) {
transition: opacity 0.2s;
&.closed {
opacity: 0;
width: $menu-width;
pointer-events: none;
}
}
> h1 {
position: absolute;
right: 0;
top: 0;
width: $menu-width;
height: 2.5rem;
line-height: 2.5rem;
margin: 0;
padding: 0.25rem;
text-align: center;
font-family: inherit;
font-size: 1.2rem;
font-weight: bold;
box-shadow: 0 0 5px #00000088;
z-index: 10;
@media (max-width: $menu-width) {
width: 100%;
}
}
> .close-button {
z-index: 20;
right: calc(375px - 2.5rem);
top: 0.5rem;
@media (max-width: $menu-width) {
left: 0.5rem;
top: 0.5rem;
}
}
> .content {
position: absolute;
right: 0;
top: 3rem;
display: flex;
flex-direction: column;
width: calc(375px - 1rem);
height: calc(100% - 4rem);
padding: 0.5rem;
overflow-y: auto;
@media (max-width: $menu-width) {
width: calc(100% - 1rem);
}
> * {
flex-grow: 0;
flex-shrink: 0;
}
> .separator {
position: relative;
left: -0.5rem;
width: calc(100% + 1rem);
border-top: solid 1px $line_color;
margin: 0.5rem 0;
&.greedy {
flex-grow: 1;
border-bottom: solid 1px $line_color;
}
}
> .label {
min-height: 0;
font-size: 0.8rem;
padding: 1rem 0.5rem 0.1rem 1rem;
line-height: 0.8rem;
}
> .dropdown > .select {
border: solid 1px $line_color;
border-top: none;
width: calc(100% - 2px);
}
// a little hacky to force not displaying any icon
> .toggle-button.icon {
> .label {
display: inline;
}
> img {
display: none;
}
> .switch {
display: block;
}
&.selected:not(:hover) {
background-color: $normal_bg;
color: $normal_fg;
}
&:hover {
background-color: $hover_bg;
color: $hover_fg;
}
}
> .footer-separator{
flex-grow: 1;
}
> .footer {
margin: 0.5rem -0.5rem -0.5rem -0.5rem;
padding: 0 0.5rem 0.5rem 0.5rem;
border-top: solid 1px $line_color;
line-height: 1rem;
font-size: 0.8rem;
white-space: normal;
h1 {
margin: 1rem 0 0.5rem 0;
font-size: 1rem;
text-align: center;
}
h2 {
margin: 1rem 0 0 0;
font-size: inherit;
}
p {
margin: 0 0 0.5rem 0;
&:last-child {
margin-bottom: 0;
}
}
}
}
}

View File

@ -1,39 +0,0 @@
.bluemap-container .ui .ui-element.position {
flex-basis: 6rem;
flex-shrink: 1;
min-width: 4rem;
display: flex;
height: 1rem;
> input {
width: calc(100% - 2rem);
height: 100%;
padding: 0 0.5rem 0 0;
font: inherit;
color: inherit;
background: transparent;
border: none;
outline: none;
// remove number spinner firefox
-moz-appearance:textfield;
// remove number spinner webkit
&::-webkit-inner-spin-button,
&::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
}
&[data-axis]::before {
padding: 0 0.2rem 0 0.5rem;
line-height: 2rem;
color: $label_fg;
content: attr(data-axis)':';
}
}

View File

@ -1,9 +0,0 @@
.bluemap-container .ui .ui-element.separator {
pointer-events: none;
min-width: 0;
min-height: 0;
padding: 0;
background-color: unset;
}

View File

@ -1,23 +0,0 @@
.bluemap-container .ui .ui-element.slider {
display: flex;
align-content: stretch;
> input {
box-sizing: border-box;
width: 100%;
padding: 0;
margin: 0 0.5rem;
}
> .label {
margin: 0 0.5rem;
min-width: 4rem;
flex-grow: 0;
text-align: right;
}
}

View File

@ -1,76 +0,0 @@
.bluemap-container .ui .ui-element.toggle-button {
&:not(.icon) {
padding-right: 2.75rem;
}
&:active {
background-color: $hover_bg;
color: $hover_fg;
> img {
filter: invert(0);
}
}
&.icon {
&.selected {
background-color: $active_bg;
color: $active_fg;
> img {
filter: invert(1);
}
}
}
> .switch {
position: absolute;
right: 0.5rem;
top: 50%;
transform: translate(0, -50%);
height: 1rem;
width: 1.75rem;
border-radius: 1rem;
background-color: $normal_fg;
transition: background-color 0.2s;
&::after {
position: absolute;
content: '';
top: 0;
left: 0;
height: 0.8rem;
width: 0.8rem;
margin: 0.1rem;
border-radius: 100%;
background-color: $normal_bg;
transition: left 0.2s;
}
}
&.selected > .switch {
background-color: #008800;
&::after {
left: calc(100% - 1rem);
}
}
&.icon > .switch {
display: none;
}
}

View File

@ -1,96 +0,0 @@
.bluemap-container .ui .toolbar {
display: flex;
align-items: stretch;
//justify-content: center;
width: calc(100% - 20px);
margin: 10px;
pointer-events: none;
@media (max-width: $small-max) {
width: 100%;
margin: 0;
background-color: $normal_bg;
> .mobile-hide {
display: none;
}
}
@media (max-width: $super-small-max) {
flex-wrap: wrap;
}
> * {
pointer-events: auto;
}
> .ui-element {
flex-shrink: 0;
background-color: $normal_bg;
color: $normal_fg;
@media (max-width: $small-max) {
border-top: solid 1px $line_color;
margin-top: -1px;
}
@media (max-width: $super-small-max) {
flex-grow: 1;
}
}
> .ui-element:not(.separator) + .ui-element:not(.separator) {
border-left: solid 1px $line_color;
margin-left: -1px;
}
> .ui-element.separator {
width: 10px;
flex-shrink: 0;
@media (max-width: $small-max) {
width: 0;
border-left: solid 1px $line_color;
margin-left: -1px;
}
@media (max-width: $super-small-max) {
display: none;
}
}
> .ui-element.separator.greedy {
flex-grow: 1;
@media (max-width: $small-max) {
border-right: solid 1px $line_color;
margin-right: -1px;
z-index: 101;
}
@media (max-width: $super-small-max) {
display: unset;
border-right: none;
margin-right: 0;
flex-grow: 0;
}
}
> .ui-element.dropdown {
flex-basis: 15rem;
flex-shrink: 1;
min-width: 10rem;
@media (max-width: $super-small-max) {
flex-basis: calc(100% - 2rem); //space for dropdown + menu button
}
}
}

View File

@ -1,96 +0,0 @@
.bluemap-container .ui {
position: relative;
h1, h2, h3, h4, h5, h6 {
font-size: 1rem;
font-weight: bold;
text-decoration: none;
text-align: left;
margin: 0;
padding: 0;
}
h1 {
font-size: 1.5rem;
}
h2 {
font-size: 1.3rem;
}
h3 {
font-size: 1.1rem;
}
p {
padding: 0;
margin: 0.5rem 0 0 0;
}
.close-button {
position: absolute;
top: 0;
right: 0;
width: 1.5rem;
height: 1.5rem;
margin: 0.25rem;
font-weight: bold;
&::after, &::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0.8rem;
height: 0.2rem;
background-color: $normal_fg;
}
&::before {
transform: translate(-50%, -50%) rotate(45deg);
}
&::after {
transform: translate(-50%, -50%) rotate(-45deg);
}
&:hover::after, &:hover::before {
background-color: darkred;
}
}
.alert-box {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
pointer-events: none;
.alert {
position: relative;
padding: 1rem;
margin: 1rem;
background-color: $normal_bg;
color: $normal_fg;
pointer-events: all;
}
}
}

View File

@ -1,14 +0,0 @@
{
"compilerOptions": {
"sourceMap": true,
"module": "esnext",
"target": "es6",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"allowJs": true
},
"include": [ "src" ]
}

View File

@ -1,81 +0,0 @@
const path = require('path')
const fs = require('fs')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const WEBROOT_PATH = path.resolve(__dirname, 'src/main/webroot')
const BUILD_PATH = path.resolve(__dirname, 'build/generated/webroot')
// folder with a generated world to render in the dev server
const WORLD_DATA_PATH = path.resolve(__dirname, '../data/test-render')
module.exports = {
mode: 'production',
devtool: 'source-map',
entry: {
'bluemap': path.resolve(WEBROOT_PATH, 'js/site.js'),
},
output: {
path: BUILD_PATH,
filename: 'js/[name].js',
},
devServer: {
contentBase: WORLD_DATA_PATH,
compress: true,
port: 8080,
hot: true,
host: '0.0.0.0'
},
plugins: [
new MiniCssExtractPlugin({
filename: 'style/[name].css?[hash]',
}),
new HtmlWebpackPlugin({
template: path.resolve(WEBROOT_PATH, 'index.html'),
favicon: path.resolve(WEBROOT_PATH, 'assets/favicon.png'),
hash: true,
}),
],
resolve: {
extensions: ['.js', '.css', '.scss'],
},
module: {
rules: [
// Transpile JavaScript source files using TypeScript engine
{
test: /\.(js|ts)$/,
include: /src/,
use: 'ts-loader',
},
// Just import normal css files
{
test: /\.css$/,
include: /src/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{ loader: 'css-loader' },
],
},
// Converts scss files into css to use within custom elements
{
test: /\.scss$/,
include: /src/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{ loader: 'css-loader' },
{ loader: 'sass-loader' },
],
},
// Load additional files
{
test: /\.(png|svg)(\?.*$|$)/,
include: /src/,
use: [
{
loader: 'file-loader',
options: { name: 'assets/[name].[ext]?[hash]' },
},
],
},
],
},
}