mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-24 03:25:17 +01:00
Merge branch 'master' into mc/1.12
This commit is contained in:
commit
eac678669b
2
.github/workflows/gradle.yml
vendored
2
.github/workflows/gradle.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
|||||||
- name: Test with Gradle
|
- name: Test with Gradle
|
||||||
run: ./gradlew test
|
run: ./gradlew test
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: ./gradlew shadowJar
|
run: ./gradlew build
|
||||||
- uses: actions/upload-artifact@v1
|
- uses: actions/upload-artifact@v1
|
||||||
with:
|
with:
|
||||||
name: artifact
|
name: artifact
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -20,6 +20,9 @@ bin/*
|
|||||||
.project
|
.project
|
||||||
*/.project
|
*/.project
|
||||||
|
|
||||||
|
node_modules/
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
# exclude generated resource
|
# exclude generated resource
|
||||||
BlueMapCore/src/main/resources/webroot.zip
|
BlueMapCore/src/main/resources/webroot.zip
|
||||||
BlueMapCore/src/main/resources/resourceExtensions.zip
|
BlueMapCore/src/main/resources/resourceExtensions.zip
|
@ -1,3 +1,7 @@
|
|||||||
|
plugins {
|
||||||
|
id 'com.moowork.node' version '1.3.1'
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'com.google.guava:guava:21.0'
|
compile 'com.google.guava:guava:21.0'
|
||||||
compile 'com.google.code.gson:gson:2.8.0'
|
compile 'com.google.code.gson:gson:2.8.0'
|
||||||
@ -12,13 +16,42 @@ dependencies {
|
|||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node {
|
||||||
|
version = '12.14.1'
|
||||||
|
download = true
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
task zipWebroot(type: Zip) {
|
||||||
from fileTree('src/main/webroot')
|
from fileTree('build/generated/webroot/')
|
||||||
archiveName 'webroot.zip'
|
archiveName 'webroot.zip'
|
||||||
destinationDir(file('src/main/resources/'))
|
destinationDir(file('src/main/resources/'))
|
||||||
outputs.upToDateWhen { false }
|
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'
|
||||||
|
}
|
||||||
|
|
||||||
task zipResourceExtensions(type: Zip) {
|
task zipResourceExtensions(type: Zip) {
|
||||||
from fileTree('src/main/resourceExtensions')
|
from fileTree('src/main/resourceExtensions')
|
||||||
archiveName 'resourceExtensions.zip'
|
archiveName 'resourceExtensions.zip'
|
||||||
@ -27,5 +60,5 @@ task zipResourceExtensions(type: Zip) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//always update the zip before build
|
//always update the zip before build
|
||||||
compileJava.dependsOn(zipWebroot)
|
processResources.dependsOn(buildWebroot)
|
||||||
compileJava.dependsOn(zipResourceExtensions)
|
processResources.dependsOn(zipResourceExtensions)
|
||||||
|
42
BlueMapCore/package.json
Normal file
42
BlueMapCore/package.json
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"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,22 +1,10 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset=utf-8>
|
<meta charset="utf-8">
|
||||||
<title>BlueMap</title>
|
<title>BlueMap</title>
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="style/style.css?v=2">
|
|
||||||
|
|
||||||
<script src="js/libs/jquery.min.js"></script>
|
|
||||||
<script type="text/javascript" src="js/libs/three.min.js"></script>
|
|
||||||
<script type="text/javascript" src="js/libs/bluemap.js"></script>
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="map-container"></div>
|
<div id="map-container"></div>
|
||||||
|
|
||||||
<script type="text/javascript" src="js/site.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
483
BlueMapCore/src/main/webroot/js/libs/BlueMap.js
Normal file
483
BlueMapCore/src/main/webroot/js/libs/BlueMap.js
Normal file
@ -0,0 +1,483 @@
|
|||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
AmbientLight,
|
||||||
|
BackSide,
|
||||||
|
BufferGeometryLoader,
|
||||||
|
ClampToEdgeWrapping,
|
||||||
|
CubeGeometry,
|
||||||
|
DirectionalLight,
|
||||||
|
FileLoader,
|
||||||
|
FrontSide,
|
||||||
|
Mesh,
|
||||||
|
MeshBasicMaterial,
|
||||||
|
MeshLambertMaterial,
|
||||||
|
NormalBlending,
|
||||||
|
NearestFilter,
|
||||||
|
PerspectiveCamera,
|
||||||
|
Scene,
|
||||||
|
Texture,
|
||||||
|
TextureLoader,
|
||||||
|
VertexColors,
|
||||||
|
WebGLRenderer,
|
||||||
|
} from 'three';
|
||||||
|
|
||||||
|
import Compass from './modules/Compass.js';
|
||||||
|
import Info from './modules/Info.js';
|
||||||
|
import MapMenu from './modules/MapMenu.js';
|
||||||
|
import Position from './modules/Position.js';
|
||||||
|
import Settings from './modules/Settings.js';
|
||||||
|
|
||||||
|
import Controls from './Controls.js';
|
||||||
|
import TileManager from './TileManager.js';
|
||||||
|
|
||||||
|
import { stringToImage, pathFromCoords } from './utils.js';
|
||||||
|
|
||||||
|
import SKYBOX_NORTH from '../../assets/skybox/north.png';
|
||||||
|
import SKYBOX_SOUTH from '../../assets/skybox/south.png';
|
||||||
|
import SKYBOX_EAST from '../../assets/skybox/east.png';
|
||||||
|
import SKYBOX_WEST from '../../assets/skybox/west.png';
|
||||||
|
import SKYBOX_UP from '../../assets/skybox/up.png';
|
||||||
|
import SKYBOX_DOWN from '../../assets/skybox/down.png';
|
||||||
|
|
||||||
|
export default class BlueMap {
|
||||||
|
constructor(element, dataRoot) {
|
||||||
|
this.element = element;
|
||||||
|
this.dataRoot = dataRoot;
|
||||||
|
|
||||||
|
this.loadingNoticeElement = $('<div id="bluemap-loading" class="box">loading...</div>').appendTo($(this.element));
|
||||||
|
|
||||||
|
this.fileLoader = new FileLoader();
|
||||||
|
this.blobLoader = new FileLoader();
|
||||||
|
this.blobLoader.setResponseType('blob');
|
||||||
|
this.bufferGeometryLoader = new BufferGeometryLoader();
|
||||||
|
|
||||||
|
this.initStage();
|
||||||
|
this.locationHash = '';
|
||||||
|
this.controls = new Controls(this.camera, this.element, this.hiresScene);
|
||||||
|
|
||||||
|
this.loadSettings().then(async () => {
|
||||||
|
this.lowresTileManager = new TileManager(
|
||||||
|
this,
|
||||||
|
this.settings[this.map]['lowres']['viewDistance'],
|
||||||
|
this.loadLowresTile,
|
||||||
|
this.lowresScene,
|
||||||
|
this.settings[this.map]['lowres']['tileSize'],
|
||||||
|
{x: 0, z: 0}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.hiresTileManager = new TileManager(
|
||||||
|
this,
|
||||||
|
this.settings[this.map]['hires']['viewDistance'],
|
||||||
|
this.loadHiresTile,
|
||||||
|
this.hiresScene,
|
||||||
|
this.settings[this.map]['hires']['tileSize'],
|
||||||
|
{x: 0, z: 0}
|
||||||
|
);
|
||||||
|
|
||||||
|
await this.loadHiresMaterial();
|
||||||
|
await this.loadLowresMaterial();
|
||||||
|
|
||||||
|
this.initModules();
|
||||||
|
this.start();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initModules() {
|
||||||
|
this.modules = {};
|
||||||
|
this.modules.compass = new Compass(this);
|
||||||
|
this.modules.position = new Position(this);
|
||||||
|
this.modules.mapMenu = new MapMenu(this);
|
||||||
|
this.modules.info = new Info(this);
|
||||||
|
this.modules.settings = new Settings(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeMap(map) {
|
||||||
|
this.hiresTileManager.close();
|
||||||
|
this.lowresTileManager.close();
|
||||||
|
|
||||||
|
this.map = map;
|
||||||
|
this.controls.resetPosition();
|
||||||
|
|
||||||
|
this.lowresTileManager = new TileManager(
|
||||||
|
this,
|
||||||
|
this.settings[this.map]['lowres']['viewDistance'],
|
||||||
|
this.loadLowresTile,
|
||||||
|
this.lowresScene,
|
||||||
|
this.settings[this.map]['lowres']['tileSize'],
|
||||||
|
{x: 0, z: 0}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.hiresTileManager = new TileManager(
|
||||||
|
this,
|
||||||
|
this.settings[this.map]['hires']['viewDistance'],
|
||||||
|
this.loadHiresTile,
|
||||||
|
this.hiresScene,
|
||||||
|
this.settings[this.map]['hires']['tileSize'],
|
||||||
|
{x: 0, z: 0}
|
||||||
|
);
|
||||||
|
|
||||||
|
this.lowresTileManager.update();
|
||||||
|
this.hiresTileManager.update();
|
||||||
|
|
||||||
|
document.dispatchEvent(new Event('bluemap-map-change'));
|
||||||
|
}
|
||||||
|
|
||||||
|
loadLocationHash() {
|
||||||
|
let hashVars = window.location.hash.substring(1).split(':');
|
||||||
|
if (hashVars.length >= 1){
|
||||||
|
if (this.settings[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;
|
||||||
|
this.controls.direction = this.controls.targetDirection;
|
||||||
|
this.controls.distance = this.controls.targetDistance;
|
||||||
|
this.controls.angle = this.controls.targetAngle;
|
||||||
|
this.controls.targetPosition.y = this.controls.minHeight;
|
||||||
|
this.controls.position.copy(this.controls.targetPosition);
|
||||||
|
}
|
||||||
|
if (hashVars.length >= 7){
|
||||||
|
let height = parseInt(hashVars[6]);
|
||||||
|
if (!isNaN(height)){
|
||||||
|
this.controls.minHeight = height;
|
||||||
|
this.controls.targetPosition.y = height;
|
||||||
|
this.controls.position.copy(this.controls.targetPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.loadingNoticeElement.remove();
|
||||||
|
|
||||||
|
this.loadLocationHash();
|
||||||
|
|
||||||
|
$(window).on('hashchange', () => {
|
||||||
|
if (this.locationHash === window.location.hash) return;
|
||||||
|
this.loadLocationHash();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
this.render();
|
||||||
|
|
||||||
|
this.lowresTileManager.update();
|
||||||
|
this.hiresTileManager.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
update = () => {
|
||||||
|
setTimeout(this.update, 1000);
|
||||||
|
|
||||||
|
this.lowresTileManager.setPosition(this.controls.targetPosition);
|
||||||
|
this.hiresTileManager.setPosition(this.controls.targetPosition);
|
||||||
|
|
||||||
|
this.locationHash =
|
||||||
|
'#' + 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.targetPosition.y);
|
||||||
|
history.replaceState(undefined, undefined, this.locationHash);
|
||||||
|
};
|
||||||
|
|
||||||
|
render = () => {
|
||||||
|
requestAnimationFrame(this.render);
|
||||||
|
|
||||||
|
if (this.controls.update()) this.updateFrame = true;
|
||||||
|
|
||||||
|
if (!this.updateFrame) return;
|
||||||
|
this.updateFrame = false;
|
||||||
|
|
||||||
|
document.dispatchEvent(new Event('bluemap-update-frame'));
|
||||||
|
|
||||||
|
this.skyboxCamera.rotation.copy(this.camera.rotation);
|
||||||
|
this.skyboxCamera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
this.renderer.clear();
|
||||||
|
this.renderer.render(this.skyboxScene, this.skyboxCamera, this.renderer.getRenderTarget(), false);
|
||||||
|
this.renderer.clearDepth();
|
||||||
|
this.renderer.render(this.lowresScene, this.camera, this.renderer.getRenderTarget(), false);
|
||||||
|
if (this.camera.position.y < 400) {
|
||||||
|
this.renderer.clearDepth();
|
||||||
|
this.renderer.render(this.hiresScene, this.camera, this.renderer.getRenderTarget(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.updateFrame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadSettings() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.fileLoader.load(this.dataRoot + 'settings.json', settings => {
|
||||||
|
this.settings = JSON.parse(settings);
|
||||||
|
this.maps = [];
|
||||||
|
for (let map in this.settings) {
|
||||||
|
if (this.settings.hasOwnProperty(map) && this.settings[map].enabled){
|
||||||
|
this.maps.push(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.maps.sort((map1, map2) => {
|
||||||
|
var sort = this.settings[map1].ordinal - this.settings[map2].ordinal;
|
||||||
|
if (isNaN(sort)) return 0;
|
||||||
|
return sort;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.map = this.maps[0];
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initStage() {
|
||||||
|
this.updateFrame = true;
|
||||||
|
this.quality = 1;
|
||||||
|
|
||||||
|
this.renderer = new WebGLRenderer({
|
||||||
|
alpha: true,
|
||||||
|
antialias: true,
|
||||||
|
sortObjects: false,
|
||||||
|
preserveDrawingBuffer: true,
|
||||||
|
logarithmicDepthBuffer: true,
|
||||||
|
});
|
||||||
|
this.renderer.autoClear = false;
|
||||||
|
|
||||||
|
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.ambient = new AmbientLight(0xffffff, 1);
|
||||||
|
this.skyboxScene.add(this.skyboxScene.ambient);
|
||||||
|
this.skyboxScene.add(this.createSkybox());
|
||||||
|
|
||||||
|
this.lowresScene = new Scene();
|
||||||
|
this.lowresScene.ambient = new AmbientLight(0xffffff, 0.6);
|
||||||
|
this.lowresScene.add(this.lowresScene.ambient);
|
||||||
|
this.lowresScene.sunLight = new DirectionalLight(0xccccbb, 0.7);
|
||||||
|
this.lowresScene.sunLight.position.set(1, 5, 3);
|
||||||
|
this.lowresScene.add(this.lowresScene.sunLight);
|
||||||
|
|
||||||
|
this.hiresScene = new Scene();
|
||||||
|
this.hiresScene.ambient = new AmbientLight(0xffffff, 1);
|
||||||
|
this.hiresScene.add(this.hiresScene.ambient);
|
||||||
|
this.hiresScene.sunLight = new DirectionalLight(0xccccbb, 0.2);
|
||||||
|
this.hiresScene.sunLight.position.set(1, 5, 3);
|
||||||
|
this.hiresScene.add(this.hiresScene.sunLight);
|
||||||
|
|
||||||
|
this.element.append(this.renderer.domElement);
|
||||||
|
this.handleContainerResize();
|
||||||
|
|
||||||
|
$(window).resize(this.handleContainerResize);
|
||||||
|
}
|
||||||
|
|
||||||
|
createSkybox() {
|
||||||
|
let geometry = new CubeGeometry(10, 10, 10);
|
||||||
|
let material = [
|
||||||
|
new MeshBasicMaterial({
|
||||||
|
map: new TextureLoader().load(SKYBOX_SOUTH),
|
||||||
|
side: BackSide
|
||||||
|
}),
|
||||||
|
new MeshBasicMaterial({
|
||||||
|
map: new TextureLoader().load(SKYBOX_NORTH),
|
||||||
|
side: BackSide
|
||||||
|
}),
|
||||||
|
new MeshBasicMaterial({
|
||||||
|
map: new TextureLoader().load(SKYBOX_UP),
|
||||||
|
side: BackSide
|
||||||
|
}),
|
||||||
|
new MeshBasicMaterial({
|
||||||
|
map: new TextureLoader().load(SKYBOX_DOWN),
|
||||||
|
side: BackSide
|
||||||
|
}),
|
||||||
|
new MeshBasicMaterial({
|
||||||
|
map: new TextureLoader().load(SKYBOX_EAST),
|
||||||
|
side: BackSide
|
||||||
|
}),
|
||||||
|
new MeshBasicMaterial({
|
||||||
|
map: new TextureLoader().load(SKYBOX_WEST),
|
||||||
|
side: BackSide
|
||||||
|
})
|
||||||
|
];
|
||||||
|
return new Mesh(geometry, material);
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadHiresMaterial() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.fileLoader.load(this.dataRoot + 'textures.json', textures => {
|
||||||
|
textures = JSON.parse(textures);
|
||||||
|
|
||||||
|
let materials = [];
|
||||||
|
for (let i = 0; i < textures['textures'].length; i++) {
|
||||||
|
let t = textures['textures'][i];
|
||||||
|
|
||||||
|
let material = new MeshLambertMaterial({
|
||||||
|
transparent: t['transparent'],
|
||||||
|
alphaTest: 0.01,
|
||||||
|
depthWrite: true,
|
||||||
|
depthTest: true,
|
||||||
|
blending: NormalBlending,
|
||||||
|
vertexColors: VertexColors,
|
||||||
|
side: FrontSide,
|
||||||
|
wireframe: false
|
||||||
|
});
|
||||||
|
|
||||||
|
let texture = new Texture();
|
||||||
|
texture.image = stringToImage(t['texture']);
|
||||||
|
|
||||||
|
texture.premultiplyAlpha = false;
|
||||||
|
texture.generateMipmaps = false;
|
||||||
|
texture.magFilter = NearestFilter;
|
||||||
|
texture.minFilter = NearestFilter;
|
||||||
|
texture.wrapS = ClampToEdgeWrapping;
|
||||||
|
texture.wrapT = ClampToEdgeWrapping;
|
||||||
|
texture.flipY = false;
|
||||||
|
texture.needsUpdate = true;
|
||||||
|
texture.flatShading = true;
|
||||||
|
|
||||||
|
material.map = texture;
|
||||||
|
material.needsUpdate = true;
|
||||||
|
|
||||||
|
materials[i] = material;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hiresMaterial = materials;
|
||||||
|
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadLowresMaterial() {
|
||||||
|
this.lowresMaterial = new MeshLambertMaterial({
|
||||||
|
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';
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.bufferGeometryLoader.load(path, geometry => {
|
||||||
|
let object = new Mesh(geometry, this.hiresMaterial);
|
||||||
|
|
||||||
|
let tileSize = this.settings[this.map]['hires']['tileSize'];
|
||||||
|
let translate = this.settings[this.map]['hires']['translate'];
|
||||||
|
let scale = this.settings[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';
|
||||||
|
|
||||||
|
return new Promise((reslove, reject) => {
|
||||||
|
this.bufferGeometryLoader.load(path, geometry => {
|
||||||
|
let object = new Mesh(geometry, this.lowresMaterial);
|
||||||
|
|
||||||
|
let tileSize = this.settings[this.map]['lowres']['tileSize'];
|
||||||
|
let translate = this.settings[this.map]['lowres']['translate'];
|
||||||
|
let scale = this.settings[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);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ###### UI ######
|
||||||
|
|
||||||
|
alert(content) {
|
||||||
|
let alertBox = $('#alert-box');
|
||||||
|
if (alertBox.length === 0){
|
||||||
|
alertBox = $('<div id="alert-box"></div>').appendTo(this.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
let displayAlert = () => {
|
||||||
|
let alert = $(`<div class="alert box" style="display: none;"><div class="alert-close-button"></div>${content}</div>`).appendTo(alertBox);
|
||||||
|
alert.find('.alert-close-button').click(() => {
|
||||||
|
alert.fadeOut(200, () => alert.remove());
|
||||||
|
});
|
||||||
|
alert.fadeIn(200);
|
||||||
|
};
|
||||||
|
|
||||||
|
let oldAlerts = alertBox.find('.alert');
|
||||||
|
if (oldAlerts.length > 0){
|
||||||
|
alertBox.fadeOut(200, () => {
|
||||||
|
alertBox.html('');
|
||||||
|
alertBox.show();
|
||||||
|
displayAlert();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
displayAlert();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
297
BlueMapCore/src/main/webroot/js/libs/Controls.js
Normal file
297
BlueMapCore/src/main/webroot/js/libs/Controls.js
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
/*
|
||||||
|
* 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 { 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.minHeight = 0;
|
||||||
|
|
||||||
|
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.keyStates = {}
|
||||||
|
this.state = Controls.STATES.NONE;
|
||||||
|
|
||||||
|
let canvas = $(this.element).find('canvas').get(0);
|
||||||
|
window.addEventListener('contextmenu', event => {
|
||||||
|
event.preventDefault();
|
||||||
|
}, false);
|
||||||
|
canvas.addEventListener('mousedown', this.onMouseDown, false);
|
||||||
|
window.addEventListener('mousemove', this.onMouseMove, false);
|
||||||
|
window.addEventListener('mouseup', this.onMouseUp, false);
|
||||||
|
canvas.addEventListener('wheel', this.onMouseWheel, false);
|
||||||
|
window.addEventListener('keydown', this.onKeyDown, false);
|
||||||
|
window.addEventListener('keyup', this.onKeyUp, false);
|
||||||
|
|
||||||
|
this.camera.position.set(0, 1000, 0);
|
||||||
|
this.camera.lookAt(this.position);
|
||||||
|
this.camera.updateProjectionMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
resetPosition() {
|
||||||
|
this.position = new Vector3(0, 70, 0);
|
||||||
|
this.targetPosition = new Vector3(0, 70, 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 zoomLerp = (this.distance - 100) / 200;
|
||||||
|
if (zoomLerp < 0) zoomLerp = 0;
|
||||||
|
if (zoomLerp > 1) zoomLerp = 1;
|
||||||
|
this.targetPosition.y = 300 * zoomLerp + this.minHeight * (1 - zoomLerp);
|
||||||
|
|
||||||
|
this.position.x += (this.targetPosition.x - this.position.x) * this.settings.move.smooth;
|
||||||
|
this.position.y += (this.targetPosition.y - 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() {
|
||||||
|
//TODO: this can be performance-improved by only intersecting the correct tile?
|
||||||
|
|
||||||
|
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(this.heightScene.children);
|
||||||
|
if (intersects.length > 0){
|
||||||
|
this.minHeight = intersects[0].point.y;
|
||||||
|
//this.targetPosition.y = this.minHeight;
|
||||||
|
} else {
|
||||||
|
//this.targetPosition.y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rayStart.set(this.camera.position.x, 300, this.camera.position.z);
|
||||||
|
this.raycaster.set(rayStart, this.rayDirection);
|
||||||
|
intersects.length = 0;
|
||||||
|
intersects = this.raycaster.intersectObjects(this.heightScene.children);
|
||||||
|
if (intersects.length > 0){
|
||||||
|
if (intersects[0].point.y > this.minHeight){
|
||||||
|
this.minHeight = intersects[0].point.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
updateMouseMoves = () => {
|
||||||
|
this.deltaMouse.set(this.lastMouse.x - this.mouse.x, this.lastMouse.y - this.mouse.y);
|
||||||
|
|
||||||
|
this.moveDelta.x = 0;
|
||||||
|
this.moveDelta.y = 0;
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown = event => {
|
||||||
|
this.keyStates[event.keyCode] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyUp = e => {
|
||||||
|
this.keyStates[event.keyCode] = false;
|
||||||
|
}
|
||||||
|
}
|
59
BlueMapCore/src/main/webroot/js/libs/Tile.js
Normal file
59
BlueMapCore/src/main/webroot/js/libs/Tile.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
184
BlueMapCore/src/main/webroot/js/libs/TileManager.js
Normal file
184
BlueMapCore/src/main/webroot/js/libs/TileManager.js
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
* 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, position) {
|
||||||
|
this.blueMap = blueMap;
|
||||||
|
this.viewDistance = viewDistance;
|
||||||
|
this.tileLoader = tileLoader;
|
||||||
|
this.scene = scene;
|
||||||
|
this.tileSize = new Vector2(tileSize.x, tileSize.z);
|
||||||
|
|
||||||
|
this.tile = new Vector2(position.x, position.z);
|
||||||
|
this.lastTile = this.tile.clone();
|
||||||
|
|
||||||
|
this.closed = false;
|
||||||
|
this.currentlyLoading = 0;
|
||||||
|
this.updateTimeout = null;
|
||||||
|
|
||||||
|
this.tiles = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
setPosition(center) {
|
||||||
|
this.tile.set(center.x, center.z).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 vd = this.viewDistance;
|
||||||
|
|
||||||
|
if (
|
||||||
|
tile.x + vd < this.tile.x ||
|
||||||
|
tile.x - vd > this.tile.x ||
|
||||||
|
tile.z + vd < this.tile.y ||
|
||||||
|
tile.z - vd > this.tile.y
|
||||||
|
) {
|
||||||
|
tile.disposeModel();
|
||||||
|
delete this.tiles[keys[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 < this.viewDistance * 2) {
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
53
BlueMapCore/src/main/webroot/js/libs/modules/Compass.js
Normal file
53
BlueMapCore/src/main/webroot/js/libs/modules/Compass.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* 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 { getTopLeftElement } from './Module.js';
|
||||||
|
|
||||||
|
import COMPASS from '../../../assets/compass.svg';
|
||||||
|
|
||||||
|
export default class Compass {
|
||||||
|
constructor(blueMap) {
|
||||||
|
this.blueMap = blueMap;
|
||||||
|
|
||||||
|
$('#bluemap-compass').remove();
|
||||||
|
this.element = $(`<div id="bluemap-compass" class="button"><img id="bluemap-compass-needle" src="${COMPASS}" /></div>`).appendTo(getTopLeftElement(blueMap));
|
||||||
|
this.needle = $('#bluemap-compass-needle');
|
||||||
|
|
||||||
|
$(document).on('bluemap-update-frame', this.onBlueMapUpdateFrame);
|
||||||
|
$(this.element).click(this.onClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlueMapUpdateFrame = () => {
|
||||||
|
this.needle.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;
|
||||||
|
}
|
||||||
|
}
|
49
BlueMapCore/src/main/webroot/js/libs/modules/Info.js
Normal file
49
BlueMapCore/src/main/webroot/js/libs/modules/Info.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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 { getTopRightElement } from './Module.js';
|
||||||
|
|
||||||
|
export default class Info {
|
||||||
|
constructor(blueMap) {
|
||||||
|
this.blueMap = blueMap;
|
||||||
|
const parent = getTopRightElement(blueMap);
|
||||||
|
$('#bluemap-info').remove();
|
||||||
|
this.elementInfo = $('<div id="bluemap-info" class="button"></div>').appendTo(parent);
|
||||||
|
this.elementInfo.click(this.onClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick = () => {
|
||||||
|
this.blueMap.alert(
|
||||||
|
'<h1>Info</h1>' +
|
||||||
|
'Visit BlueMap on <a href="https://github.com/BlueMap-Minecraft">GitHub</a>!<br>' +
|
||||||
|
'BlueMap works best with <a href="https://www.google.com/chrome/">Chrome</a>.<br>' +
|
||||||
|
'<h2>Controls</h2>' +
|
||||||
|
'Leftclick-drag with your mouse or use the arrow-keys to navigate.<br>' +
|
||||||
|
'Rightclick-drag with your mouse to rotate your view.<br>' +
|
||||||
|
'Scroll to zoom.<br>'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
63
BlueMapCore/src/main/webroot/js/libs/modules/MapMenu.js
Normal file
63
BlueMapCore/src/main/webroot/js/libs/modules/MapMenu.js
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* 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 { getTopLeftElement } from './Module.js';
|
||||||
|
|
||||||
|
export default class MapMenu {
|
||||||
|
constructor(blueMap) {
|
||||||
|
this.bluemap = blueMap;
|
||||||
|
const maps = this.bluemap.settings;
|
||||||
|
|
||||||
|
$('#bluemap-mapmenu').remove();
|
||||||
|
this.element = $(`<div id="bluemap-mapmenu" class="dropdown-container"><span class="selection">${maps[this.bluemap.map].name}</span></div>`).appendTo(getTopLeftElement(blueMap));
|
||||||
|
|
||||||
|
const dropdown = $('<div class="dropdown"></div>').appendTo(this.element);
|
||||||
|
this.maplist = $('<ul></ul>').appendTo(dropdown);
|
||||||
|
|
||||||
|
for (let mapId in maps) {
|
||||||
|
if (!maps.hasOwnProperty(mapId)) continue;
|
||||||
|
const map = maps[mapId];
|
||||||
|
if (!map.enabled) continue;
|
||||||
|
|
||||||
|
$(`<li map="${mapId}">${map.name}</li>`).appendTo(this.maplist);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.maplist.find('li[map=' + this.bluemap.map + ']').hide();
|
||||||
|
this.maplist.find('li[map]').click(this.onMapClick);
|
||||||
|
$(document).on('bluemap-map-change', this.onBlueMapMapChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMapClick = event => {
|
||||||
|
const map = $(event.target).attr('map');
|
||||||
|
this.bluemap.changeMap(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlueMapMapChange = () => {
|
||||||
|
this.maplist.find('li').show();
|
||||||
|
this.maplist.find('li[map=' + this.bluemap.map + ']').hide();
|
||||||
|
this.element.find('.selection').html(this.bluemap.settings[this.bluemap.map].name);
|
||||||
|
}
|
||||||
|
}
|
47
BlueMapCore/src/main/webroot/js/libs/modules/Module.js
Normal file
47
BlueMapCore/src/main/webroot/js/libs/modules/Module.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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';
|
||||||
|
|
||||||
|
// ###### Modules ######
|
||||||
|
|
||||||
|
export const getTopRightElement = blueMap => {
|
||||||
|
let element = $('#bluemap-topright');
|
||||||
|
|
||||||
|
if (element.length === 0){
|
||||||
|
element = $('<div id="bluemap-topright" class="box"></div>').appendTo(blueMap.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getTopLeftElement = blueMap => {
|
||||||
|
let element = $('#bluemap-topleft');
|
||||||
|
|
||||||
|
if (element.length === 0){
|
||||||
|
element = $('<div id="bluemap-topleft" class="box"></div>').appendTo(blueMap.element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
};
|
47
BlueMapCore/src/main/webroot/js/libs/modules/Position.js
Normal file
47
BlueMapCore/src/main/webroot/js/libs/modules/Position.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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 { getTopLeftElement } from './Module.js';
|
||||||
|
|
||||||
|
export default class Position {
|
||||||
|
constructor(blueMap) {
|
||||||
|
this.blueMap = blueMap;
|
||||||
|
const parent = getTopLeftElement(blueMap);
|
||||||
|
|
||||||
|
$('.bluemap-position').remove();
|
||||||
|
this.elementX = $('<div class="bluemap-position pos-x">0</div>').appendTo(parent);
|
||||||
|
//this.elementY = $('<div class="bluemap-position pos-y">0</div>').appendTo(parent);
|
||||||
|
this.elementZ = $('<div class="bluemap-position pos-z">0</div>').appendTo(parent);
|
||||||
|
|
||||||
|
$(document).on('bluemap-update-frame', this.onBlueMapUpdateFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlueMapUpdateFrame = () => {
|
||||||
|
this.elementX.html(Math.floor(this.blueMap.controls.targetPosition.x));
|
||||||
|
//this.elementY.html(this.blueMap.controls.targetPosition.y === 0 ? '-' : Math.floor(this.blueMap.controls.targetPosition.y));
|
||||||
|
this.elementZ.html(Math.floor(this.blueMap.controls.targetPosition.z));
|
||||||
|
}
|
||||||
|
}
|
122
BlueMapCore/src/main/webroot/js/libs/modules/Settings.js
Normal file
122
BlueMapCore/src/main/webroot/js/libs/modules/Settings.js
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* 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 { Math as Math3 } from 'three';
|
||||||
|
|
||||||
|
import { getTopRightElement } from './Module.js';
|
||||||
|
|
||||||
|
import GEAR from '../../../assets/gear.svg';
|
||||||
|
|
||||||
|
export default class Settings {
|
||||||
|
constructor(blueMap) {
|
||||||
|
this.blueMap = blueMap;
|
||||||
|
const parent = getTopRightElement(blueMap);
|
||||||
|
|
||||||
|
$('#bluemap-settings').remove();
|
||||||
|
this.elementMenu = $('<div id="bluemap-settings-container" style="display: none"></div>').appendTo(parent);
|
||||||
|
this.elementSettings = $(`<div id="bluemap-settings" class="button"><img src="${GEAR}" /></div>`).appendTo(parent);
|
||||||
|
this.elementSettings.click(this.onSettingsClick);
|
||||||
|
|
||||||
|
/* Quality */
|
||||||
|
|
||||||
|
this.elementQuality = $(
|
||||||
|
'<div id="bluemap-settings-quality" class="dropdown-container"><span class="selection">Quality: <span>Normal</span></span><div class="dropdown"><ul>' +
|
||||||
|
'<li quality="2">High</li>' +
|
||||||
|
'<li quality="1" style="display: none">Normal</li>' +
|
||||||
|
'<li quality="0.75">Fast</li>' +
|
||||||
|
'</ul></div></div>'
|
||||||
|
).prependTo(this.elementMenu);
|
||||||
|
|
||||||
|
this.elementQuality.find('li[quality]').click(this.onQualityClick);
|
||||||
|
this.elementRenderDistance = $('<div id="bluemap-settings-render-distance" class="dropdown-container"></div>').prependTo(this.elementMenu);
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
$(document).on('bluemap-map-change', this.init);
|
||||||
|
}
|
||||||
|
|
||||||
|
init = () => {
|
||||||
|
this.defaultHighRes = this.blueMap.hiresTileManager.viewDistance;
|
||||||
|
this.defaultLowRes = this.blueMap.lowresTileManager.viewDistance;
|
||||||
|
|
||||||
|
this.elementRenderDistance.html(
|
||||||
|
'<span class="selection">View Distance: <span>' + this.blueMap.hiresTileManager.viewDistance + '</span></span>' +
|
||||||
|
'<div class="dropdown">' +
|
||||||
|
'<input type="range" min="0" max="100" step="1" value="' + this.renderDistanceToPct(this.blueMap.hiresTileManager.viewDistance, this.defaultHighRes) + '" />' +
|
||||||
|
'</div>'
|
||||||
|
);
|
||||||
|
|
||||||
|
this.slider = this.elementRenderDistance.find('input');
|
||||||
|
this.slider.on('change input', this.onViewDistanceSlider);
|
||||||
|
};
|
||||||
|
|
||||||
|
onViewDistanceSlider = () => {
|
||||||
|
this.blueMap.hiresTileManager.viewDistance = this.pctToRenderDistance(parseFloat(this.slider.val()), this.defaultHighRes);
|
||||||
|
this.blueMap.lowresTileManager.viewDistance = this.pctToRenderDistance(parseFloat(this.slider.val()), this.defaultLowRes);
|
||||||
|
this.elementRenderDistance.find('.selection > span').html(Math.round(this.blueMap.hiresTileManager.viewDistance * 10) / 10);
|
||||||
|
|
||||||
|
this.blueMap.lowresTileManager.update();
|
||||||
|
this.blueMap.hiresTileManager.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
onQualityClick = (event) => {
|
||||||
|
const target = event.target
|
||||||
|
const desc = $(target).html();
|
||||||
|
this.blueMap.quality = parseFloat($(target).attr('quality'));
|
||||||
|
|
||||||
|
this.elementQuality.find('li').show();
|
||||||
|
this.elementQuality.find(`li[quality="${this.blueMap.quality}"]`).hide();
|
||||||
|
|
||||||
|
this.elementQuality.find('.selection > span').html(desc);
|
||||||
|
|
||||||
|
this.blueMap.handleContainerResize();
|
||||||
|
};
|
||||||
|
|
||||||
|
onSettingsClick = () => {
|
||||||
|
if (this.elementMenu.css('display') === 'none'){
|
||||||
|
this.elementSettings.addClass('active');
|
||||||
|
} else {
|
||||||
|
this.elementSettings.removeClass('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.elementMenu.animate({
|
||||||
|
width: 'toggle'
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
pctToRenderDistance(value, defaultValue) {
|
||||||
|
let max = defaultValue * 5;
|
||||||
|
if (max > 20) max = 20;
|
||||||
|
|
||||||
|
return Math3.mapLinear(value, 0, 100, 1, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderDistanceToPct(value, defaultValue) {
|
||||||
|
let max = defaultValue * 5;
|
||||||
|
if (max > 20) max = 20;
|
||||||
|
|
||||||
|
return Math3.mapLinear(value, 1, max, 0, 100);
|
||||||
|
}
|
||||||
|
}
|
946
BlueMapCore/src/main/webroot/js/libs/three.min.js
vendored
946
BlueMapCore/src/main/webroot/js/libs/three.min.js
vendored
File diff suppressed because one or more lines are too long
66
BlueMapCore/src/main/webroot/js/libs/utils.js
Normal file
66
BlueMapCore/src/main/webroot/js/libs/utils.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* 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 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 = 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}`;
|
||||||
|
|
||||||
|
export const Vector2_ZERO = new Vector2(0, 0);
|
||||||
|
export const Vector3_ZERO = new Vector3(0, 0, 0);
|
@ -1,6 +1,8 @@
|
|||||||
// global variable to enable access through browser console
|
import $ from 'jquery';
|
||||||
var blueMap;
|
import BlueMap from './libs/BlueMap.js';
|
||||||
|
|
||||||
$(document).ready(function () {
|
import '../style/style.scss';
|
||||||
blueMap = new BlueMap($("#map-container")[0], "data/");
|
|
||||||
|
$(document).ready(() => {
|
||||||
|
window.blueMap = new BlueMap($('#map-container')[0], 'data/');
|
||||||
});
|
});
|
||||||
|
71
BlueMapCore/src/main/webroot/style/modules/alertbox.scss
Normal file
71
BlueMapCore/src/main/webroot/style/modules/alertbox.scss
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#alert-box {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: column;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
padding: 15px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
padding: 15px 0 5px 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #333333;
|
||||||
|
text-decoration: underline;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #888888;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
position: relative;
|
||||||
|
pointer-events: all;
|
||||||
|
margin: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.alert-close-button {
|
||||||
|
/*position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
*/
|
||||||
|
margin: -10px -10px 0px 0px;
|
||||||
|
padding: 0 0 5px 5px;
|
||||||
|
float: right;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
line-height: 15px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 15px;
|
||||||
|
color: #333333;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: 'x';
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #dd3333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
BlueMapCore/src/main/webroot/style/modules/compass.scss
Normal file
8
BlueMapCore/src/main/webroot/style/modules/compass.scss
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#bluemap-compass {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
|
||||||
|
&:hover #bluemap-compass-needle {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
}
|
10
BlueMapCore/src/main/webroot/style/modules/info.scss
Normal file
10
BlueMapCore/src/main/webroot/style/modules/info.scss
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#bluemap-info {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: 'i';
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
7
BlueMapCore/src/main/webroot/style/modules/mapmenu.scss
Normal file
7
BlueMapCore/src/main/webroot/style/modules/mapmenu.scss
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#bluemap-mapmenu {
|
||||||
|
width: 200px;
|
||||||
|
|
||||||
|
.selection, .dropdown li {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
41
BlueMapCore/src/main/webroot/style/modules/settings.scss
Normal file
41
BlueMapCore/src/main/webroot/style/modules/settings.scss
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#bluemap-settings {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-settings.active:not(:hover) {
|
||||||
|
background-color: #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-settings:hover > img {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-settings-container {
|
||||||
|
display: flex;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-settings-quality {
|
||||||
|
width: 150px;
|
||||||
|
height: 30px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-settings-quality .selection, #bluemap-settings-quality .dropdown li {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-settings-render-distance {
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-settings-render-distance .selection {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-settings-render-distance input {
|
||||||
|
width: calc(100% - 20px);
|
||||||
|
margin: 10px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
@ -1,290 +0,0 @@
|
|||||||
html, body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
font-size: 15px;
|
|
||||||
line-height: 15px;
|
|
||||||
font-family: Verdana,Helvetica,Arial,sans-serif;
|
|
||||||
|
|
||||||
color: #333333;
|
|
||||||
background-color: #dddddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.box {
|
|
||||||
color: #333333;
|
|
||||||
background-color: white;
|
|
||||||
box-shadow: 0px 1px 4px 0px rgba(50, 50, 50, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
background-color: white;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button:hover {
|
|
||||||
background-color: #333333;
|
|
||||||
color: #dddddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-container {
|
|
||||||
background-color: white;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-container:hover {
|
|
||||||
background-color: #dddddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-container > .dropdown {
|
|
||||||
position: absolute;
|
|
||||||
background-color: white;
|
|
||||||
color: #333333;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
transition: all 0.3s;
|
|
||||||
max-height: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-container:hover > .dropdown {
|
|
||||||
max-height: 200px;
|
|
||||||
border-color: #ddddddFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-container > .dropdown > ul {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-container > .dropdown > ul > li {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-container > .dropdown > ul > li:hover {
|
|
||||||
color: #dddddd;
|
|
||||||
background-color: #333333;
|
|
||||||
}
|
|
||||||
|
|
||||||
#alert-box {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
align-content: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
flex-direction: column;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#alert-box h1 {
|
|
||||||
font-size: 1.4rem;
|
|
||||||
font-weight: bold;
|
|
||||||
|
|
||||||
margin: 0;
|
|
||||||
padding: 15px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#alert-box h2 {
|
|
||||||
font-size: 1.2rem;
|
|
||||||
font-weight: bold;
|
|
||||||
|
|
||||||
margin: 0;
|
|
||||||
padding: 15px 0 5px 0;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
#alert-box a {
|
|
||||||
color: #333333;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
#alert-box a:hover {
|
|
||||||
color: #888888;
|
|
||||||
}
|
|
||||||
|
|
||||||
#alert-box .alert {
|
|
||||||
position: relative;
|
|
||||||
pointer-events: all;
|
|
||||||
margin: 10px;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#alert-box .alert .alert-close-button {
|
|
||||||
/*position: absolute;
|
|
||||||
top: 5px;
|
|
||||||
right: 5px;
|
|
||||||
*/
|
|
||||||
margin: -10px -10px 0px 0px;
|
|
||||||
padding: 0 0 5px 5px;
|
|
||||||
float: right;
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
line-height: 15px;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 15px;
|
|
||||||
color: #333333;
|
|
||||||
}
|
|
||||||
|
|
||||||
#alert-box .alert .alert-close-button::after {
|
|
||||||
content: 'x';
|
|
||||||
}
|
|
||||||
|
|
||||||
#alert-box .alert .alert-close-button:hover {
|
|
||||||
color: #dd3333;
|
|
||||||
}
|
|
||||||
|
|
||||||
#map-container {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: black;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#map-container canvas {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-loading {
|
|
||||||
position: absolute;
|
|
||||||
width: 200px;
|
|
||||||
line-height: 20px;
|
|
||||||
padding: 20px 0;
|
|
||||||
top: calc(50% - 31px);
|
|
||||||
left: calc(50% - 101px);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-topright {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
right: 10px;
|
|
||||||
|
|
||||||
line-height: 30px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-topright > *:not(:last-child) {
|
|
||||||
border-right: solid 1px #dddddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-topleft {
|
|
||||||
position: absolute;
|
|
||||||
top: 10px;
|
|
||||||
left: 10px;
|
|
||||||
|
|
||||||
line-height: 30px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-topleft > *:not(:last-child) {
|
|
||||||
border-right: solid 1px #dddddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-mapmenu {
|
|
||||||
width: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-mapmenu .selection, #bluemap-mapmenu .dropdown li {
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-compass {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-compass:hover #bluemap-compass-needle {
|
|
||||||
filter: invert(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.bluemap-position {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
width: 60px;
|
|
||||||
height: 30px;
|
|
||||||
padding: 0 5px 0 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bluemap-position::before {
|
|
||||||
position: absolute;
|
|
||||||
left: 7px;
|
|
||||||
color: #888888;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bluemap-position.pos-x::before {
|
|
||||||
content: "x:";
|
|
||||||
}
|
|
||||||
|
|
||||||
.bluemap-position.pos-y::before {
|
|
||||||
content: "y:";
|
|
||||||
}
|
|
||||||
|
|
||||||
.bluemap-position.pos-z::before {
|
|
||||||
content: "z:";
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-settings {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-settings.active:not(:hover) {
|
|
||||||
background-color: #dddddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-settings:hover > img {
|
|
||||||
filter: invert(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-settings-container {
|
|
||||||
display: flex;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-settings-quality {
|
|
||||||
width: 150px;
|
|
||||||
height: 30px;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-settings-quality .selection, #bluemap-settings-quality .dropdown li {
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-settings-render-distance {
|
|
||||||
width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-settings-render-distance .selection {
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-settings-render-distance input {
|
|
||||||
width: calc(100% - 20px);
|
|
||||||
margin: 10px;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-info {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#bluemap-info::after {
|
|
||||||
content: 'i';
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
153
BlueMapCore/src/main/webroot/style/style.scss
Normal file
153
BlueMapCore/src/main/webroot/style/style.scss
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
@import "./modules/alertbox.scss";
|
||||||
|
@import "./modules/compass.scss";
|
||||||
|
@import "./modules/info.scss";
|
||||||
|
@import "./modules/mapmenu.scss";
|
||||||
|
@import "./modules/settings.scss";
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 15px;
|
||||||
|
font-family: Verdana,Helvetica,Arial,sans-serif;
|
||||||
|
|
||||||
|
color: #333333;
|
||||||
|
background-color: #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
color: #333333;
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 0px 1px 4px 0px rgba(50, 50, 50, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
background-color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
background-color: #333333;
|
||||||
|
color: #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-container {
|
||||||
|
background-color: white;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-container:hover {
|
||||||
|
background-color: #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-container > .dropdown {
|
||||||
|
position: absolute;
|
||||||
|
background-color: white;
|
||||||
|
color: #333333;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
transition: all 0.3s;
|
||||||
|
max-height: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-container:hover > .dropdown {
|
||||||
|
max-height: 200px;
|
||||||
|
border-color: #ddddddFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-container > .dropdown > ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-container > .dropdown > ul > li {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-container > .dropdown > ul > li:hover {
|
||||||
|
color: #dddddd;
|
||||||
|
background-color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-container {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: black;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-container canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-loading {
|
||||||
|
position: absolute;
|
||||||
|
width: 200px;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 20px 0;
|
||||||
|
top: calc(50% - 31px);
|
||||||
|
left: calc(50% - 101px);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-topright {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
|
||||||
|
line-height: 30px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-topright > *:not(:last-child) {
|
||||||
|
border-right: solid 1px #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-topleft {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
|
||||||
|
line-height: 30px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bluemap-topleft > *:not(:last-child) {
|
||||||
|
border-right: solid 1px #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bluemap-position {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
width: 60px;
|
||||||
|
height: 30px;
|
||||||
|
padding: 0 5px 0 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bluemap-position::before {
|
||||||
|
position: absolute;
|
||||||
|
left: 7px;
|
||||||
|
color: #888888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bluemap-position.pos-x::before {
|
||||||
|
content: "x:";
|
||||||
|
}
|
||||||
|
|
||||||
|
.bluemap-position.pos-y::before {
|
||||||
|
content: "y:";
|
||||||
|
}
|
||||||
|
|
||||||
|
.bluemap-position.pos-z::before {
|
||||||
|
content: "z:";
|
||||||
|
}
|
14
BlueMapCore/tsconfig.json
Normal file
14
BlueMapCore/tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"sourceMap": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "es6",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowJs": true
|
||||||
|
},
|
||||||
|
"include": [ "src" ]
|
||||||
|
}
|
79
BlueMapCore/webpack.config.js
Normal file
79
BlueMapCore/webpack.config.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
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, 'build/generated/world')
|
||||||
|
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
filename: 'style/[name].css?[hash]',
|
||||||
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: path.resolve(WEBROOT_PATH, 'index.html'),
|
||||||
|
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]' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
@ -15,7 +15,7 @@ Easy:
|
|||||||
`git clone https://github.com/BlueMap-Minecraft/BlueMap.git`
|
`git clone https://github.com/BlueMap-Minecraft/BlueMap.git`
|
||||||
|
|
||||||
### Build
|
### Build
|
||||||
In order to build BlueMap you simply need to run the `./gradlew shadowJar` command.
|
In order to build BlueMap you simply need to run the `./gradlew build` command.
|
||||||
You can find the compiled JAR file in `./build/libs`
|
You can find the compiled JAR file in `./build/libs`
|
||||||
|
|
||||||
### Issues / Suggestions
|
### Issues / Suggestions
|
||||||
|
@ -31,7 +31,7 @@ dependencies {
|
|||||||
compile project(':BlueMapSponge')
|
compile project(':BlueMapSponge')
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
assemble.dependsOn shadowJar {
|
||||||
baseName = 'BlueMap'
|
baseName = 'BlueMap'
|
||||||
version = null
|
version = null
|
||||||
classifier = null
|
classifier = null
|
||||||
|
Loading…
Reference in New Issue
Block a user