Replace the webapp with the new BlueMapVue project and adapt the build-script
3
.gitignore
vendored
@ -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
@ -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
|
||||
|
1
BlueMapCommon/BlueMapVue
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit b6a6adcf5da0bd7abe2ce7072021b93b3109b708
|
@ -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)
|
||||
|
||||
|
@ -55,7 +55,6 @@
|
||||
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;
|
||||
|
@ -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.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 void updateFiles() throws IOException {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
@ -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 |
@ -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 |
Before Width: | Height: | Size: 5.9 KiB |
@ -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 |
@ -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 |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.9 KiB |
@ -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 |
@ -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>
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
});
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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 };
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
};
|
||||
|
||||
}
|
@ -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,'&').replace(/</g,'<').replace(/>/g,'>');
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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;
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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');
|
||||
};
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
@ -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);
|
||||
});
|
||||
};
|
||||
}
|
@ -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");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
@ -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/');
|
||||
});
|
@ -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;
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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";
|
@ -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%;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
.bluemap-container .ui .ui-element.label {
|
||||
|
||||
color: $label_fg;
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)':';
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
.bluemap-container .ui .ui-element.separator {
|
||||
pointer-events: none;
|
||||
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
|
||||
background-color: unset;
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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" ]
|
||||
}
|
@ -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]' },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|