Introduce shaders to improve rendering, add night and rework the ui
@ -216,6 +216,11 @@ private void createElementFace(ExtendedModel model, Direction faceDir, Vector3f
|
||||
float blockLight = bl.getBlockLightLevel();
|
||||
float sunLight = bl.getSunLightLevel();
|
||||
|
||||
if (faceDir == Direction.UP) {
|
||||
blockLight = block.getBlockLightLevel();
|
||||
sunLight = block.getSunLightLevel();
|
||||
}
|
||||
|
||||
f1.setC1(color);
|
||||
f1.setC2(color);
|
||||
f1.setC3(color);
|
||||
|
12
BlueMapCore/src/main/webroot/assets/burger.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?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>
|
After Width: | Height: | Size: 1.1 KiB |
13
BlueMapCore/src/main/webroot/assets/night.svg
Normal file
@ -0,0 +1,13 @@
|
||||
<?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>
|
After Width: | Height: | Size: 975 B |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 4.5 KiB |
@ -24,31 +24,24 @@
|
||||
*/
|
||||
import $ from 'jquery';
|
||||
import {
|
||||
AmbientLight,
|
||||
BackSide,
|
||||
BufferGeometryLoader,
|
||||
ClampToEdgeWrapping,
|
||||
CubeGeometry,
|
||||
DirectionalLight,
|
||||
SphereGeometry,
|
||||
FileLoader,
|
||||
FrontSide,
|
||||
Mesh,
|
||||
MeshBasicMaterial,
|
||||
NearestFilter,
|
||||
NearestMipmapLinearFilter,
|
||||
NearestMipMapLinearFilter,
|
||||
PerspectiveCamera,
|
||||
Scene,
|
||||
ShaderMaterial,
|
||||
Texture,
|
||||
TextureLoader,
|
||||
VertexColors,
|
||||
WebGLRenderer, ShaderMaterial,
|
||||
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 UI from './ui/UI.js';
|
||||
|
||||
import Controls from './Controls.js';
|
||||
import TileManager from './TileManager.js';
|
||||
@ -57,22 +50,29 @@ 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 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.element = $('<div class="bluemap-container"></div>').appendTo(element)[0];
|
||||
this.dataRoot = dataRoot;
|
||||
|
||||
this.loadingNoticeElement = $('<div id="bluemap-loading" class="box">loading...</div>').appendTo($(this.element));
|
||||
this.hiresViewDistance = 160;
|
||||
this.lowresViewDistance = 3200;
|
||||
this.targetSunLightStrength = 1;
|
||||
this.sunLightStrength = {
|
||||
value: this.targetSunLightStrength
|
||||
};
|
||||
this.mobSpawnOverlay = {
|
||||
value: false
|
||||
};
|
||||
|
||||
this.ui = new UI(this);
|
||||
|
||||
this.loadingNoticeElement = $('<div>loading...</div>').appendTo($(this.element));
|
||||
window.onerror = this.onLoadError;
|
||||
|
||||
this.fileLoader = new FileLoader();
|
||||
@ -88,26 +88,18 @@ export default class BlueMap {
|
||||
await this.loadHiresMaterial();
|
||||
await this.loadLowresMaterial();
|
||||
|
||||
this.changeMap(this.map);
|
||||
this.changeMap(this.maps[0]);
|
||||
|
||||
this.initModules();
|
||||
this.ui.load();
|
||||
this.start();
|
||||
}).catch(error => {
|
||||
this.onLoadError(error.toString());
|
||||
console.error(error);
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
if (this.map === map) return;
|
||||
|
||||
if (this.hiresTileManager !== undefined) this.hiresTileManager.close();
|
||||
if (this.lowresTileManager !== undefined) this.lowresTileManager.close();
|
||||
|
||||
@ -118,8 +110,6 @@ export default class BlueMap {
|
||||
z: this.settings[this.map]["startPos"]["z"]
|
||||
};
|
||||
|
||||
this.targetSunLightStrength = 1;
|
||||
|
||||
this.controls.setTileSize(this.settings[this.map]['hires']['tileSize']);
|
||||
this.controls.resetPosition();
|
||||
this.controls.targetPosition.set(startPos.x, this.controls.targetPosition.y, startPos.z);
|
||||
@ -127,7 +117,7 @@ export default class BlueMap {
|
||||
|
||||
this.lowresTileManager = new TileManager(
|
||||
this,
|
||||
this.settings[this.map]['lowres']['viewDistance'],
|
||||
this.lowresViewDistance,
|
||||
this.loadLowresTile,
|
||||
this.lowresScene,
|
||||
this.settings[this.map]['lowres']['tileSize'],
|
||||
@ -136,7 +126,7 @@ export default class BlueMap {
|
||||
|
||||
this.hiresTileManager = new TileManager(
|
||||
this,
|
||||
this.settings[this.map]['hires']['viewDistance'],
|
||||
this.hiresViewDistance,
|
||||
this.loadHiresTile,
|
||||
this.hiresScene,
|
||||
this.settings[this.map]['hires']['tileSize'],
|
||||
@ -233,9 +223,9 @@ export default class BlueMap {
|
||||
if (this.controls.update()) this.updateFrame = true;
|
||||
|
||||
//update lighting
|
||||
let targetLight = 1;
|
||||
if (this.camera.position.y < 400){
|
||||
targetLight = this.targetSunLightStrength;
|
||||
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;
|
||||
@ -295,7 +285,6 @@ export default class BlueMap {
|
||||
return sort;
|
||||
});
|
||||
|
||||
this.map = this.maps[0];
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
@ -305,11 +294,6 @@ export default class BlueMap {
|
||||
this.updateFrame = true;
|
||||
this.quality = 1;
|
||||
|
||||
this.targetSunLightStrength = 1;
|
||||
this.sunLightStrength = {
|
||||
value: this.targetSunLightStrength
|
||||
};
|
||||
|
||||
this.renderer = new WebGLRenderer({
|
||||
alpha: true,
|
||||
antialias: true,
|
||||
@ -331,40 +315,22 @@ export default class BlueMap {
|
||||
this.lowresScene = new Scene();
|
||||
this.hiresScene = new Scene();
|
||||
|
||||
this.element.append(this.renderer.domElement);
|
||||
$(this.renderer.domElement).addClass("map-canvas").appendTo(this.element);
|
||||
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
|
||||
})
|
||||
];
|
||||
let geometry = new SphereGeometry(10, 10, 10);
|
||||
let material = new ShaderMaterial({
|
||||
uniforms: {
|
||||
sunlightStrength: this.sunLightStrength
|
||||
},
|
||||
vertexShader: SKY_VERTEX_SHADER,
|
||||
fragmentShader: SKY_FRAGMENT_SHADER,
|
||||
side: BackSide
|
||||
});
|
||||
return new Mesh(geometry, material);
|
||||
}
|
||||
|
||||
@ -385,7 +351,7 @@ export default class BlueMap {
|
||||
texture.anisotropy = 1;
|
||||
texture.generateMipmaps = opaque || transparent;
|
||||
texture.magFilter = NearestFilter;
|
||||
texture.minFilter = texture.generateMipmaps ? NearestMipmapLinearFilter : NearestFilter;
|
||||
texture.minFilter = texture.generateMipmaps ? NearestMipMapLinearFilter : NearestFilter;
|
||||
texture.wrapS = ClampToEdgeWrapping;
|
||||
texture.wrapT = ClampToEdgeWrapping;
|
||||
texture.flipY = false;
|
||||
@ -397,7 +363,8 @@ export default class BlueMap {
|
||||
type: 't',
|
||||
value: texture
|
||||
},
|
||||
sunlightStrength: this.sunLightStrength
|
||||
sunlightStrength: this.sunLightStrength,
|
||||
mobSpawnOverlay: this.mobSpawnOverlay
|
||||
};
|
||||
|
||||
let material = new ShaderMaterial({
|
||||
@ -423,12 +390,10 @@ export default class BlueMap {
|
||||
}
|
||||
|
||||
async loadLowresMaterial() {
|
||||
let uniforms = {
|
||||
sunlightStrength: this.sunLightStrength
|
||||
};
|
||||
|
||||
this.lowresMaterial = new ShaderMaterial({
|
||||
uniforms: uniforms,
|
||||
uniforms: {
|
||||
sunlightStrength: this.sunLightStrength
|
||||
},
|
||||
vertexShader: LOWRES_VERTEX_SHADER,
|
||||
fragmentShader: LOWRES_FRAGMENT_SHADER,
|
||||
transparent: false,
|
||||
@ -486,7 +451,7 @@ export default class BlueMap {
|
||||
this.loadingNoticeElement.remove();
|
||||
|
||||
this.toggleAlert(undefined, `
|
||||
<div style="max-width: 500px">
|
||||
<div style="max-width: 50rem">
|
||||
<h1>Error</h1>
|
||||
<p style="color: red; font-family: monospace">${message}</p>
|
||||
</div>
|
||||
@ -496,14 +461,14 @@ export default class BlueMap {
|
||||
// ###### UI ######
|
||||
|
||||
toggleAlert(id, content) {
|
||||
let alertBox = $('#alert-box');
|
||||
let alertBox = $(this.element).find('.alert-box');
|
||||
if (alertBox.length === 0){
|
||||
alertBox = $('<div id="alert-box"></div>').appendTo(this.element);
|
||||
alertBox = $('<div class="alert-box"></div>').appendTo(this.ui.hud);
|
||||
}
|
||||
|
||||
let displayAlert = () => {
|
||||
let alert = $(`<div class="alert box" data-alert-id="${id}" style="display: none;"><div class="alert-close-button"></div>${content}</div>`).appendTo(alertBox);
|
||||
alert.find('.alert-close-button').click(() => {
|
||||
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);
|
||||
|
@ -32,10 +32,10 @@ import { hashTile } from './utils.js';
|
||||
export default class TileManager {
|
||||
constructor(blueMap, viewDistance, tileLoader, scene, tileSize, position) {
|
||||
this.blueMap = blueMap;
|
||||
this.viewDistance = viewDistance;
|
||||
this.tileSize = new Vector2(tileSize.x, tileSize.z);
|
||||
this.setViewDistance(viewDistance);
|
||||
this.tileLoader = tileLoader;
|
||||
this.scene = scene;
|
||||
this.tileSize = new Vector2(tileSize.x, tileSize.z);
|
||||
|
||||
this.tile = new Vector2(0, 0);
|
||||
this.tile.set(position.x, position.z).divide(this.tileSize).floor();
|
||||
@ -48,6 +48,11 @@ export default class TileManager {
|
||||
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).divide(this.tileSize).floor();
|
||||
|
||||
@ -75,16 +80,19 @@ export default class TileManager {
|
||||
|
||||
let tile = this.tiles[keys[i]];
|
||||
|
||||
let vd = this.viewDistance;
|
||||
let vdx = this.viewDistanceX;
|
||||
let vdz = this.viewDistanceZ;
|
||||
|
||||
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.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -98,6 +106,8 @@ export default class TileManager {
|
||||
tile.disposeModel();
|
||||
delete this.tiles[keys[i]];
|
||||
}
|
||||
|
||||
this.blueMap.updateFrame = true;
|
||||
}
|
||||
|
||||
close() {
|
||||
@ -122,7 +132,7 @@ export default class TileManager {
|
||||
let d = 1;
|
||||
let m = 1;
|
||||
|
||||
while (m < this.viewDistance * 2) {
|
||||
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;
|
||||
@ -140,6 +150,8 @@ export default class TileManager {
|
||||
|
||||
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);
|
||||
|
||||
|
@ -24,24 +24,28 @@
|
||||
*/
|
||||
import $ from 'jquery';
|
||||
|
||||
import { getTopLeftElement } from './Module.js';
|
||||
import Button from '../ui/Button.js';
|
||||
|
||||
import COMPASS from '../../../assets/compass.svg';
|
||||
|
||||
export default class Compass {
|
||||
export default class Compass extends Button {
|
||||
constructor(blueMap) {
|
||||
super(undefined, undefined, COMPASS);
|
||||
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);
|
||||
}
|
||||
|
||||
createElement(){
|
||||
let element = super.createElement();
|
||||
element.click(this.onClick);
|
||||
return element;
|
||||
}
|
||||
|
||||
onBlueMapUpdateFrame = () => {
|
||||
this.needle.css('transform', `rotate(${this.blueMap.controls.direction}rad)`);
|
||||
this.elements.forEach(element => {
|
||||
element.find("img").css('transform', `rotate(${this.blueMap.controls.direction}rad)`);
|
||||
});
|
||||
};
|
||||
|
||||
onClick = () => {
|
||||
|
@ -24,40 +24,39 @@
|
||||
*/
|
||||
import $ from 'jquery';
|
||||
|
||||
import { getTopLeftElement } from './Module.js';
|
||||
import Dropdown from "../ui/Dropdown";
|
||||
|
||||
export default class MapMenu {
|
||||
constructor(blueMap) {
|
||||
this.bluemap = blueMap;
|
||||
export default class MapSelection extends Dropdown {
|
||||
constructor(bluemap) {
|
||||
super(undefined);
|
||||
super.onChange = this.onChangeMap;
|
||||
|
||||
this.bluemap = bluemap;
|
||||
|
||||
//add maps
|
||||
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.addOption(mapId, map.name);
|
||||
}
|
||||
|
||||
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);
|
||||
createElement() {
|
||||
let element = super.createElement();
|
||||
element.addClass("map-selection");
|
||||
return element;
|
||||
}
|
||||
|
||||
onChangeMap = value => {
|
||||
this.bluemap.changeMap(value);
|
||||
};
|
||||
|
||||
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);
|
||||
this.select(this.bluemap.map);
|
||||
};
|
||||
}
|
@ -24,26 +24,34 @@
|
||||
*/
|
||||
import $ from 'jquery';
|
||||
|
||||
import { getTopRightElement } from './Module.js';
|
||||
import ToggleButton from '../ui/ToggleButton.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);
|
||||
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);
|
||||
}
|
||||
|
||||
onClick = () => {
|
||||
this.blueMap.toggleAlert('bluemap-info',
|
||||
'<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>'
|
||||
);
|
||||
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();
|
||||
}
|
||||
};
|
||||
}
|
@ -24,38 +24,34 @@
|
||||
*/
|
||||
import $ from 'jquery';
|
||||
|
||||
import { getTopLeftElement } from './Module.js';
|
||||
import Element from "../ui/Element";
|
||||
|
||||
export default class Position {
|
||||
constructor(blueMap) {
|
||||
export default class Position extends Element {
|
||||
constructor(blueMap, axis) {
|
||||
super();
|
||||
this.blueMap = blueMap;
|
||||
this.axis = axis;
|
||||
|
||||
$('.bluemap-position').remove();
|
||||
this.elements = [
|
||||
this.createPositionElement('x'),
|
||||
null,//this.elementY = this.createPositionElement('y');
|
||||
this.createPositionElement('z'),
|
||||
];
|
||||
|
||||
$(document).on('bluemap-update-frame', this.onBlueMapUpdateFrame);
|
||||
$(document).on('bluemap-update-frame', this.update);
|
||||
}
|
||||
|
||||
/** Creates the position display */
|
||||
createPositionElement(type) {
|
||||
const parent = getTopLeftElement(this.blueMap);
|
||||
const element = $(`<div class="bluemap-position" data-pos="${type}"><input type="number" value="0" /></div>`)
|
||||
.appendTo(parent)
|
||||
.children()
|
||||
.first();
|
||||
element.on('input', this.onInput(type));
|
||||
element.on('keydown', this.onKeyDown);
|
||||
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 = type => event => {
|
||||
onInput = event => {
|
||||
const value = Number(event.target.value);
|
||||
if (!isNaN(value)) {
|
||||
this.blueMap.controls.targetPosition[type] = value;
|
||||
this.blueMap.controls.targetPosition[this.axis] = value;
|
||||
this.update();
|
||||
}
|
||||
};
|
||||
|
||||
@ -63,14 +59,11 @@ export default class Position {
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
onBlueMapUpdateFrame = () => {
|
||||
const { x, y, z } = this.blueMap.controls.targetPosition;
|
||||
const values = [ z, y, x ];
|
||||
for (let element of this.elements) {
|
||||
const value = Math.floor(values.pop());
|
||||
if (element) {
|
||||
element.val(value);
|
||||
}
|
||||
}
|
||||
update = () => {
|
||||
const val = Math.floor(this.blueMap.controls.targetPosition[this.axis]);
|
||||
|
||||
this.elements.forEach(element => {
|
||||
element.find("input").val(val);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -1,122 +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 { 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 data-quality="2">High</li>' +
|
||||
'<li data-quality="1" style="display: none">Normal</li>' +
|
||||
'<li data-quality="0.75">Fast</li>' +
|
||||
'</ul></div></div>'
|
||||
).prependTo(this.elementMenu);
|
||||
|
||||
this.elementQuality.find('li[data-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('data-quality'));
|
||||
|
||||
this.elementQuality.find('li').show();
|
||||
this.elementQuality.find(`li[data-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);
|
||||
}
|
||||
}
|
@ -26,8 +26,10 @@
|
||||
const HIRES_FRAGMENT_SHADER = `
|
||||
uniform sampler2D texture;
|
||||
uniform float sunlightStrength;
|
||||
uniform bool mobSpawnOverlay;
|
||||
|
||||
varying vec3 vPosition;
|
||||
varying vec3 vWorldPosition;
|
||||
varying vec3 vNormal;
|
||||
varying vec2 vUv;
|
||||
varying vec3 vColor;
|
||||
@ -35,12 +37,34 @@ 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){
|
||||
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;
|
||||
@ -48,7 +72,7 @@ void main() {
|
||||
//apply light
|
||||
float light = max(vSunlight * sunlightStrength, vBlocklight);
|
||||
color.rgb *= light / 15.0;
|
||||
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
||||
`;
|
||||
|
@ -29,6 +29,7 @@ attribute float sunlight;
|
||||
attribute float blocklight;
|
||||
|
||||
varying vec3 vPosition;
|
||||
varying vec3 vWorldPosition;
|
||||
varying vec3 vNormal;
|
||||
varying vec2 vUv;
|
||||
varying vec3 vColor;
|
||||
@ -38,6 +39,7 @@ varying float vBlocklight;
|
||||
|
||||
void main() {
|
||||
vPosition = position;
|
||||
vWorldPosition = (vec4(position, 1) * modelMatrix).xyz;
|
||||
vNormal = normal;
|
||||
vUv = uv;
|
||||
vColor = color;
|
||||
@ -47,8 +49,9 @@ void main() {
|
||||
|
||||
gl_Position =
|
||||
projectionMatrix *
|
||||
modelViewMatrix *
|
||||
vec4(position, 1);
|
||||
viewMatrix *
|
||||
modelMatrix *
|
||||
vec4(position, 1);
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
varying vec3 vPosition;
|
||||
|
||||
void main() {
|
||||
vec4 dayColor = vec4(0.49, 0.67, 1.0, 1.0);
|
||||
vec4 nightColor = vec4(0.0, 0.02, 0.05, 1.0);
|
||||
|
||||
vec4 color = dayColor * sunlightStrength + nightColor * (1.0 - sunlightStrength);
|
||||
color.rgb *= (clamp(vPosition.y, -0.02, 0.02) + 0.02) * 25.0;
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
||||
`;
|
||||
|
||||
export default SKY_FRAGMENT_SHADER;
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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;
|
63
BlueMapCore/src/main/webroot/js/libs/ui/Button.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 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
130
BlueMapCore/src/main/webroot/js/libs/ui/Dropdown.js
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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
|
||||
option.parents(".select").slideUp(200);
|
||||
|
||||
if (event !== undefined) event.stopPropagation();
|
||||
|
||||
if (this.onChange !== undefined && this.onChange !== null){
|
||||
this.onChange(this.value, this);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -24,24 +24,16 @@
|
||||
*/
|
||||
import $ from 'jquery';
|
||||
|
||||
// ###### Modules ######
|
||||
export default class Element {
|
||||
|
||||
export const getTopRightElement = blueMap => {
|
||||
let element = $('#bluemap-topright');
|
||||
|
||||
if (element.length === 0){
|
||||
element = $('<div id="bluemap-topright" class="box"></div>').appendTo(blueMap.element);
|
||||
constructor() {
|
||||
this.elements = [];
|
||||
}
|
||||
|
||||
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);
|
||||
createElement() {
|
||||
let newElement = $('<div class="ui-element"></div>');
|
||||
this.elements.push(newElement);
|
||||
return newElement;
|
||||
}
|
||||
|
||||
return element;
|
||||
};
|
||||
}
|
42
BlueMapCore/src/main/webroot/js/libs/ui/Label.js
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
71
BlueMapCore/src/main/webroot/js/libs/ui/Menu.js
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 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());
|
||||
});
|
||||
}
|
||||
|
||||
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');
|
||||
};
|
||||
|
||||
}
|
58
BlueMapCore/src/main/webroot/js/libs/ui/Separator.js
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
86
BlueMapCore/src/main/webroot/js/libs/ui/Slider.js
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
74
BlueMapCore/src/main/webroot/js/libs/ui/ToggleButton.js
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
55
BlueMapCore/src/main/webroot/js/libs/ui/Toolbar.js
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
115
BlueMapCore/src/main/webroot/js/libs/ui/UI.js
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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 '../modules/MenuButton.js';
|
||||
import Compass from "../modules/Compass";
|
||||
import Position from "../modules/Position";
|
||||
import Button from "./Button";
|
||||
import Slider from "./Slider";
|
||||
import ToggleButton from "./ToggleButton";
|
||||
import MapSelection from "../modules/MapSeletion";
|
||||
|
||||
import NIGHT from '../../../assets/night.svg';
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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-spawnable overlay", 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");
|
||||
quality.addOption("1", "normal", true);
|
||||
quality.addOption("0.5", "low");
|
||||
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();
|
||||
});
|
||||
|
||||
//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);
|
||||
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.update();
|
||||
}
|
||||
|
||||
}
|
14
BlueMapCore/src/main/webroot/style/constants.scss
Normal file
@ -0,0 +1,14 @@
|
||||
// colors
|
||||
$normal_fg: #333;
|
||||
$normal_bg: #fff;
|
||||
|
||||
$super_light_fg: #484848;
|
||||
$super_light_bg: #ddd;
|
||||
|
||||
$light_fg: #666;
|
||||
$light_bg: #aaa;
|
||||
|
||||
// breakpoints
|
||||
$super-small-max: 500px;
|
||||
$small-max: 800px;
|
||||
$middle-max: 1200px;
|
@ -1,67 +0,0 @@
|
||||
#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 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
#bluemap-compass {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
|
||||
#bluemap-compass-needle {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&:hover #bluemap-compass-needle {
|
||||
filter: invert(1);
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
#bluemap-info {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
text-align: center;
|
||||
|
||||
&::after {
|
||||
content: 'i';
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#bluemap-mapmenu {
|
||||
width: 15rem;
|
||||
cursor: pointer;
|
||||
|
||||
.selection, .dropdown li {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
@ -1,32 +1,39 @@
|
||||
.bluemap-position {
|
||||
position: relative;
|
||||
.bluemap-container .ui .ui-element.position {
|
||||
flex-basis: 6rem;
|
||||
flex-shrink: 1;
|
||||
min-width: 4rem;
|
||||
|
||||
input {
|
||||
width: 4rem;
|
||||
height: 100%;
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
padding: 0 5px 0 25px;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
display: flex;
|
||||
|
||||
// remove number spinner firefox
|
||||
-moz-appearance:textfield;
|
||||
height: 1rem;
|
||||
|
||||
// remove number spinner webkit
|
||||
&::-webkit-inner-spin-button,
|
||||
&::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
> 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-pos]::before {
|
||||
position: absolute;
|
||||
left: 7px;
|
||||
color: #888888;
|
||||
content: attr(data-pos)':';
|
||||
}
|
||||
}
|
||||
|
||||
&[data-axis]::before {
|
||||
padding: 0 0.2rem 0 0.5rem;
|
||||
line-height: 2rem;
|
||||
color: $light_fg;
|
||||
content: attr(data-axis)':';
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
#bluemap-settings {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
|
||||
> img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#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: 2rem;
|
||||
|
||||
}
|
||||
|
||||
#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,163 +1,105 @@
|
||||
@import "./modules/alertbox.scss";
|
||||
@import "./modules/compass.scss";
|
||||
@import "./modules/info.scss";
|
||||
@import "./modules/mapmenu.scss";
|
||||
@import "./modules/position.scss";
|
||||
@import "./modules/settings.scss";
|
||||
@import "constants";
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
font-size: 15px;
|
||||
font-size: 16px;
|
||||
line-height: 1rem;
|
||||
font-family: Verdana,Helvetica,Arial,sans-serif;
|
||||
|
||||
color: #333333;
|
||||
background-color: #dddddd;
|
||||
color: $normal_fg;
|
||||
background-color: $normal_bg;
|
||||
|
||||
@media (max-width: 900px) {
|
||||
font-size: 17px;
|
||||
@media (max-width: $small-max) {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.box {
|
||||
color: #333333;
|
||||
background-color: white;
|
||||
box-shadow: 0 1px 4px 0 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: background-color 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: 0;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.bluemap-container {
|
||||
position: relative;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
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: 2rem;
|
||||
|
||||
display: flex;
|
||||
|
||||
@media (max-width: 900px) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#bluemap-topright > *:not(:last-child) {
|
||||
border-right: solid 1px #dddddd;
|
||||
}
|
||||
|
||||
#bluemap-topleft {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
|
||||
line-height: 2rem;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
display: flex;
|
||||
|
||||
@media (max-width: 900px) {
|
||||
> .map-canvas {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
>:last-child {
|
||||
flex-grow: 1;
|
||||
}
|
||||
background-color: #000;
|
||||
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
flex-wrap: wrap;
|
||||
> .ui {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
> :not(:first-child) {
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
color: $normal_fg;
|
||||
filter: drop-shadow(1px 1px 3px #0008);
|
||||
|
||||
pointer-events: none;
|
||||
|
||||
z-index: 100;
|
||||
|
||||
> * {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
>:last-child {
|
||||
> .menu {
|
||||
position: relative;
|
||||
|
||||
flex-shrink: 0;
|
||||
|
||||
filter: drop-shadow(1px 1px 3px #0008);
|
||||
|
||||
z-index: 200;
|
||||
|
||||
@media (max-width: $middle-max) {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
> .hud {
|
||||
position: relative;
|
||||
|
||||
width: 100%;
|
||||
border-top: solid 1px #dddddd;
|
||||
|
||||
pointer-events: none;
|
||||
|
||||
> * {
|
||||
pointer-events: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#bluemap-topleft > *:not(:last-child) {
|
||||
border-right: solid 1px #dddddd;
|
||||
}
|
||||
@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 "modules/position";
|
||||
|
38
BlueMapCore/src/main/webroot/style/ui/button.scss
Normal file
@ -0,0 +1,38 @@
|
||||
.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: $element_fg;
|
||||
color: $element_bg;
|
||||
|
||||
> img {
|
||||
filter: invert(1);
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: $light_fg;
|
||||
}
|
||||
|
||||
> img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
76
BlueMapCore/src/main/webroot/style/ui/dropdown.scss
Normal file
@ -0,0 +1,76 @@
|
||||
.bluemap-container .ui .ui-element.dropdown {
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
|
||||
overflow: visible;
|
||||
|
||||
user-select: none;
|
||||
|
||||
> .header {
|
||||
height: 100%;
|
||||
padding-right: 1rem;
|
||||
|
||||
&:hover {
|
||||
background-color: $light_bg;
|
||||
}
|
||||
|
||||
> .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::after {
|
||||
top: calc(50% - 0.6rem);
|
||||
border-color: transparent transparent $normal_fg transparent;
|
||||
}
|
||||
|
||||
> .select {
|
||||
position: absolute;
|
||||
top: calc(100% - 1px);
|
||||
left: 0;
|
||||
|
||||
width: calc(100% - 2px);
|
||||
overflow-x: hidden;
|
||||
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
|
||||
border: solid 1px $light_bg;
|
||||
|
||||
z-index: 110;
|
||||
|
||||
> .option {
|
||||
background-color: $super-light_bg;
|
||||
|
||||
&.selected {
|
||||
background-color: $light_bg;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $normal_fg;
|
||||
color: $normal_bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.option {
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
}
|
18
BlueMapCore/src/main/webroot/style/ui/element.scss
Normal file
@ -0,0 +1,18 @@
|
||||
$element_fg: $normal_fg;
|
||||
$element_bg: $normal_bg;
|
||||
|
||||
.bluemap-container .ui .ui-element {
|
||||
position: relative;
|
||||
|
||||
background-color: $element_bg;
|
||||
color: $element_fg;
|
||||
|
||||
min-width: 2rem;
|
||||
min-height: 2rem;
|
||||
line-height: 2rem;
|
||||
padding: 0;
|
||||
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
5
BlueMapCore/src/main/webroot/style/ui/label.scss
Normal file
@ -0,0 +1,5 @@
|
||||
.bluemap-container .ui .ui-element.label {
|
||||
|
||||
color: $light_fg;
|
||||
|
||||
}
|
114
BlueMapCore/src/main/webroot/style/ui/menu.scss
Normal file
@ -0,0 +1,114 @@
|
||||
$menu-width: 375px;
|
||||
|
||||
.bluemap-container .menu {
|
||||
position: relative;
|
||||
|
||||
height: 100%;
|
||||
width: $menu-width;
|
||||
max-width: 100%;
|
||||
|
||||
background-color: $normal_bg;
|
||||
|
||||
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: 1.5rem;
|
||||
line-height: 1.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;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
> .content {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 2rem;
|
||||
|
||||
width: $menu-width;
|
||||
height: calc(100% - 3rem);
|
||||
|
||||
padding-top: 0.5rem;
|
||||
|
||||
overflow-y: auto;
|
||||
|
||||
@media (max-width: $menu-width) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
> .separator {
|
||||
border-top: solid 1px $light_bg;
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
> .label {
|
||||
min-height: 0;
|
||||
font-size: 0.8rem;
|
||||
padding: 1rem 0.5rem 0.1rem 1rem;
|
||||
line-height: 0.8rem;
|
||||
}
|
||||
|
||||
// a little hacky to force not displaying any icon
|
||||
> .toggle-button.icon {
|
||||
> .label {
|
||||
display: inline !important;
|
||||
}
|
||||
|
||||
> img {
|
||||
display: none;
|
||||
}
|
||||
|
||||
> .switch {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
&.selected:not(:hover) {
|
||||
background-color: $normal_bg !important;
|
||||
color: $normal_fg !important;
|
||||
}
|
||||
&:hover {
|
||||
background-color: $light_bg !important;
|
||||
color: $normal_fg !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
BlueMapCore/src/main/webroot/style/ui/separator.scss
Normal file
@ -0,0 +1,10 @@
|
||||
.bluemap-container .ui .ui-element.separator {
|
||||
pointer-events: none;
|
||||
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
|
||||
background-color: unset;
|
||||
color: $element_fg;
|
||||
}
|
23
BlueMapCore/src/main/webroot/style/ui/slider.scss
Normal file
@ -0,0 +1,23 @@
|
||||
.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;
|
||||
}
|
||||
|
||||
}
|
79
BlueMapCore/src/main/webroot/style/ui/togglebutton.scss
Normal file
@ -0,0 +1,79 @@
|
||||
.bluemap-container .ui .ui-element.toggle-button {
|
||||
|
||||
&:not(.icon) {
|
||||
padding-right: 2.75rem;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
background-color: $light_bg;
|
||||
color: $normal_fg;
|
||||
}
|
||||
|
||||
&.icon {
|
||||
&:hover,
|
||||
&:active {
|
||||
background-color: $light_fg;
|
||||
color: $normal_bg;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: $normal_fg;
|
||||
color: $normal_bg;
|
||||
|
||||
> 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: $light_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: $light_bg;
|
||||
|
||||
transition: left 0.2s;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.selected > .switch {
|
||||
background-color: #008800;
|
||||
|
||||
&::after {
|
||||
left: calc(100% - 1rem);
|
||||
}
|
||||
}
|
||||
|
||||
&.icon > .switch {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
93
BlueMapCore/src/main/webroot/style/ui/toolbar.scss
Normal file
@ -0,0 +1,93 @@
|
||||
.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: $super_light_bg;
|
||||
|
||||
> .mobile-hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $super-small-max) {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
> * {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
> .ui-element {
|
||||
flex-shrink: 0;
|
||||
|
||||
@media (max-width: $small-max) {
|
||||
border-top: solid 1px $light_bg;
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
@media (max-width: $super-small-max) {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
> .ui-element:not(.separator) + .ui-element:not(.separator) {
|
||||
border-left: solid 1px $light_bg;
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
> .ui-element.separator {
|
||||
width: 10px;
|
||||
flex-shrink: 0;
|
||||
|
||||
@media (max-width: $small-max) {
|
||||
width: 0;
|
||||
border-left: solid 1px $light_bg;
|
||||
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 $light_bg;
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
95
BlueMapCore/src/main/webroot/style/ui/ui.scss
Normal file
@ -0,0 +1,95 @@
|
||||
.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: $light_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;
|
||||
|
||||
pointer-events: all;
|
||||
|
||||
background-color: $normal_bg;
|
||||
padding: 1rem;
|
||||
|
||||
margin: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -22,7 +22,8 @@ module.exports = {
|
||||
contentBase: WORLD_DATA_PATH,
|
||||
compress: true,
|
||||
port: 8080,
|
||||
hot: true
|
||||
hot: true,
|
||||
host: '0.0.0.0'
|
||||
},
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({
|
||||
|