diff --git a/.gitignore b/.gitignore
index 4cf4afab..d36fc987 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,3 +29,6 @@ package-lock.json
# exclude generated resource
BlueMapCore/src/main/resources/webroot.zip
BlueMapCore/src/main/resources/resourceExtensions.zip
+
+#exclude-test-data
+data/test-render
diff --git a/BlueMapCore/src/main/webroot/assets/poi.svg b/BlueMapCore/src/main/webroot/assets/poi.svg
new file mode 100644
index 00000000..e37b635e
--- /dev/null
+++ b/BlueMapCore/src/main/webroot/assets/poi.svg
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/BlueMapCore/src/main/webroot/js/libs/BlueMap.js b/BlueMapCore/src/main/webroot/js/libs/BlueMap.js
index b5c5ead9..df9b5097 100644
--- a/BlueMapCore/src/main/webroot/js/libs/BlueMap.js
+++ b/BlueMapCore/src/main/webroot/js/libs/BlueMap.js
@@ -42,6 +42,8 @@ import {
Vector3,
} from 'three';
+import { CSS2DRenderer } from './hud/CSS2DRenderer';
+
import UI from './ui/UI.js';
import Controls from './Controls.js';
@@ -61,6 +63,7 @@ export default class BlueMap {
constructor(element, dataRoot) {
this.element = $('
').appendTo(element)[0];
this.dataRoot = dataRoot;
+ this.locationHash = '';
this.hiresViewDistance = 160;
this.lowresViewDistance = 3200;
@@ -79,18 +82,17 @@ export default class BlueMap {
};
this.debugInfo = false;
- this.ui = new UI(this);
-
- this.loadingNoticeElement = $('loading...
').appendTo($(this.element));
- window.onerror = this.onLoadError;
-
this.fileLoader = new FileLoader();
this.blobLoader = new FileLoader();
this.blobLoader.setResponseType('blob');
this.bufferGeometryLoader = new BufferGeometryLoader();
+ this.ui = new UI(this);
+
+ this.loadingNoticeElement = $('loading...
').appendTo($(this.element));
+ window.onerror = this.onLoadError;
+
this.initStage();
- this.locationHash = '';
this.controls = new Controls(this.camera, this.element, this.hiresScene);
this.loadSettings().then(async () => {
@@ -100,16 +102,16 @@ export default class BlueMap {
this.loadUserSettings();
this.handleContainerResize();
- this.changeMap(this.maps[0]);
+ this.changeMap(this.maps[0], false);
- this.ui.load();
+ await this.ui.load();
this.start();
}).catch(error => {
this.onLoadError(error.toString());
});
}
- changeMap(map) {
+ changeMap(map, loadTiles = true) {
if (this.debugInfo) console.debug("changing map: ", map);
if (this.map === map) return;
@@ -156,13 +158,15 @@ export default class BlueMap {
startPos
);
- this.lowresTileManager.update();
- this.hiresTileManager.update();
+ if (loadTiles) {
+ this.lowresTileManager.update();
+ this.hiresTileManager.update();
+ }
document.dispatchEvent(new Event('bluemap-map-change'));
}
- loadLocationHash() {
+ loadLocationHash(smooth = false) {
let hashVars = window.location.hash.substring(1).split(':');
if (hashVars.length >= 1){
if (this.settings.maps[hashVars[0]] !== undefined && this.map !== hashVars[0]){
@@ -184,18 +188,23 @@ export default class BlueMap {
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 (!smooth) {
+ 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);
+
+ if (!smooth) {
+ this.controls.position.copy(this.controls.targetPosition);
+ }
}
}
}
@@ -207,7 +216,7 @@ export default class BlueMap {
$(window).on('hashchange', () => {
if (this.locationHash === window.location.hash) return;
- this.loadLocationHash();
+ this.loadLocationHash(true);
});
this.update();
@@ -269,13 +278,16 @@ export default class BlueMap {
this.skyboxCamera.updateProjectionMatrix();
this.renderer.clear();
- this.renderer.render(this.skyboxScene, this.skyboxCamera, this.renderer.getRenderTarget(), false);
+ this.renderer.render(this.skyboxScene, this.skyboxCamera);
this.renderer.clearDepth();
- this.renderer.render(this.lowresScene, this.camera, this.renderer.getRenderTarget(), false);
+ this.renderer.render(this.lowresScene, this.camera);
if (this.camera.position.y < 400) {
this.renderer.clearDepth();
- this.renderer.render(this.hiresScene, this.camera, this.renderer.getRenderTarget(), false);
+ this.renderer.render(this.hiresScene, this.camera);
}
+ this.renderer.render(this.shapeScene, this.camera);
+
+ this.hudRenderer.render(this.hudScene, this.camera);
};
handleContainerResize = () => {
@@ -290,6 +302,8 @@ export default class BlueMap {
.css('width', this.element.clientWidth)
.css('height', this.element.clientHeight);
+ this.hudRenderer.setSize(this.element.clientWidth, this.element.clientHeight);
+
this.updateFrame = true;
};
@@ -324,10 +338,12 @@ export default class BlueMap {
antialias: true,
sortObjects: false,
preserveDrawingBuffer: true,
- logarithmicDepthBuffer: true,
+ logarithmicDepthBuffer: false,
});
this.renderer.autoClear = false;
+ this.hudRenderer = new CSS2DRenderer();
+
this.camera = new PerspectiveCamera(75, this.element.scrollWidth / this.element.scrollHeight, 0.1, 10000);
this.camera.updateProjectionMatrix();
@@ -340,7 +356,11 @@ export default class BlueMap {
this.lowresScene = new Scene();
this.hiresScene = new Scene();
+ this.shapeScene = new Scene();
+ this.hudScene = new Scene();
+
$(this.renderer.domElement).addClass("map-canvas").appendTo(this.element);
+ $(this.hudRenderer.domElement).addClass("map-canvas-hud").appendTo(this.element);
this.handleContainerResize();
$(window).resize(this.handleContainerResize);
diff --git a/BlueMapCore/src/main/webroot/js/libs/hud/CSS2DRenderer.js b/BlueMapCore/src/main/webroot/js/libs/hud/CSS2DRenderer.js
new file mode 100644
index 00000000..c16e52a4
--- /dev/null
+++ b/BlueMapCore/src/main/webroot/js/libs/hud/CSS2DRenderer.js
@@ -0,0 +1,190 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+import {
+ Matrix4,
+ Object3D,
+ Vector3
+} from "three";
+
+var CSS2DObject = function ( element ) {
+
+ Object3D.call( this );
+
+ this.element = element;
+ this.element.style.position = 'absolute';
+
+ this.addEventListener( 'removed', function () {
+
+ this.traverse( function ( object ) {
+
+ if ( object.element instanceof Element && object.element.parentNode !== null ) {
+
+ object.element.parentNode.removeChild( object.element );
+
+ }
+
+ } );
+
+ } );
+
+};
+
+CSS2DObject.prototype = Object.create( Object3D.prototype );
+CSS2DObject.prototype.constructor = CSS2DObject;
+
+//
+
+var CSS2DRenderer = function () {
+
+ var _this = this;
+
+ var _width, _height;
+ var _widthHalf, _heightHalf;
+
+ var vector = new Vector3();
+ var viewMatrix = new Matrix4();
+ var viewProjectionMatrix = new Matrix4();
+
+ var cache = {
+ objects: new WeakMap()
+ };
+
+ var domElement = document.createElement( 'div' );
+ domElement.style.overflow = 'hidden';
+
+ this.domElement = domElement;
+
+ this.getSize = function () {
+
+ return {
+ width: _width,
+ height: _height
+ };
+
+ };
+
+ this.setSize = function ( width, height ) {
+
+ _width = width;
+ _height = height;
+
+ _widthHalf = _width / 2;
+ _heightHalf = _height / 2;
+
+ domElement.style.width = width + 'px';
+ domElement.style.height = height + 'px';
+
+ };
+
+ var renderObject = function ( object, scene, camera ) {
+
+ if ( object instanceof CSS2DObject ) {
+
+ object.onBeforeRender( _this, scene, camera );
+
+ vector.setFromMatrixPosition( object.matrixWorld );
+ vector.applyMatrix4( viewProjectionMatrix );
+
+ var element = object.element;
+ var style = 'translate(-50%,-50%) translate(' + ( vector.x * _widthHalf + _widthHalf ) + 'px,' + ( - vector.y * _heightHalf + _heightHalf ) + 'px)';
+
+ element.style.WebkitTransform = style;
+ element.style.MozTransform = style;
+ element.style.oTransform = style;
+ element.style.transform = style;
+
+ element.style.display = ( object.visible && vector.z >= - 1 && vector.z <= 1 ) ? '' : 'none';
+
+ var objectData = {
+ distanceToCameraSquared: getDistanceToSquared( camera, object )
+ };
+
+ cache.objects.set( object, objectData );
+
+ if ( element.parentNode !== domElement ) {
+
+ domElement.appendChild( element );
+
+ }
+
+ object.onAfterRender( _this, scene, camera );
+
+ }
+
+ for ( var i = 0, l = object.children.length; i < l; i ++ ) {
+
+ renderObject( object.children[ i ], scene, camera );
+
+ }
+
+ };
+
+ var getDistanceToSquared = function () {
+
+ var a = new Vector3();
+ var b = new Vector3();
+
+ return function ( object1, object2 ) {
+
+ a.setFromMatrixPosition( object1.matrixWorld );
+ b.setFromMatrixPosition( object2.matrixWorld );
+
+ return a.distanceToSquared( b );
+
+ };
+
+ }();
+
+ var filterAndFlatten = function ( scene ) {
+
+ var result = [];
+
+ scene.traverse( function ( object ) {
+
+ if ( object instanceof CSS2DObject ) result.push( object );
+
+ } );
+
+ return result;
+
+ };
+
+ var zOrder = function ( scene ) {
+
+ var sorted = filterAndFlatten( scene ).sort( function ( a, b ) {
+
+ var distanceA = cache.objects.get( a ).distanceToCameraSquared;
+ var distanceB = cache.objects.get( b ).distanceToCameraSquared;
+
+ return distanceA - distanceB;
+
+ } );
+
+ var zMax = sorted.length;
+
+ for ( var i = 0, l = sorted.length; i < l; i ++ ) {
+
+ sorted[ i ].element.style.zIndex = zMax - i;
+
+ }
+
+ };
+
+ this.render = function ( scene, camera ) {
+
+ if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
+ if ( camera.parent === null ) camera.updateMatrixWorld();
+
+ viewMatrix.copy( camera.matrixWorldInverse );
+ viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, viewMatrix );
+
+ renderObject( scene, scene, camera );
+ zOrder( scene );
+
+ };
+
+};
+
+export { CSS2DObject, CSS2DRenderer };
\ No newline at end of file
diff --git a/BlueMapCore/src/main/webroot/js/libs/modules/HudInfo.js b/BlueMapCore/src/main/webroot/js/libs/hud/HudInfo.js
similarity index 78%
rename from BlueMapCore/src/main/webroot/js/libs/modules/HudInfo.js
rename to BlueMapCore/src/main/webroot/js/libs/hud/HudInfo.js
index 6c2d9517..e226ae33 100644
--- a/BlueMapCore/src/main/webroot/js/libs/modules/HudInfo.js
+++ b/BlueMapCore/src/main/webroot/js/libs/hud/HudInfo.js
@@ -6,35 +6,56 @@ import {
Mesh,
MeshBasicMaterial
} from 'three';
+import {CSS2DObject} from './CSS2DRenderer';
import {pathFromCoords} from "../utils";
export default class HudInfo {
- constructor(blueMap, container){
+ constructor(blueMap){
this.blueMap = blueMap;
- this.container = container;
- let blockMarkerGeo = new BoxBufferGeometry( 1, 1, 1 );
+ let blockMarkerGeo = new BoxBufferGeometry( 1.01, 1.01, 1.01 );
blockMarkerGeo.translate(0.5, 0.5, 0.5);
this.blockMarker = new Mesh(blockMarkerGeo, new MeshBasicMaterial( {
color: 0xffffff,
- opacity: 0.3,
+ opacity: 0.5,
depthWrite: false,
- depthTest: false,
- transparent: true
+ transparent: true,
} ));
this.rayPosition = new Vector2();
this.raycaster = new Raycaster();
this.element = $(`
-
+
- `).appendTo(this.container);
+
+ `);
+ this.bubble = this.element.find(".bubble");
+
+ this.hudElement = new CSS2DObject(this.element[0]);
$(document).on('bluemap-info-click', this.onShowInfo);
- $(window).on('mousedown wheel', this.onHideInfo);
+ $(window).on('mousedown wheel touchstart', this.onHideInfo);
+ }
+
+ showInfoBubble(content, x, y, z, onClose) {
+ if (this.onClose){
+ this.onClose();
+ this.onClose = undefined;
+ }
+
+ this.bubble.hide();
+ this.bubble.find(".content").html(content);
+
+ this.hudElement.position.set(x, y, z);
+ this.bubble.stop();
+ this.blueMap.hudScene.add(this.hudElement);
+ this.bubble.fadeIn(200);
+
+ this.onClose = onClose;
+
+ this.blueMap.updateFrame = true;
}
onShowInfo = event => {
@@ -50,9 +71,7 @@ export default class HudInfo {
}
if (intersects.length > 0) {
- this.element.hide();
- let content = this.element.find(".content");
- content.html("");
+ let content = $("");
if (this.blueMap.debugInfo){
console.debug("Tapped position data: ", intersects[0]);
@@ -129,28 +148,28 @@ export default class HudInfo {
`).appendTo(content);
}
- //display the element
- this.element.css('left', `${event.pos.x}px`);
- this.element.css('top', `${event.pos.y}px`);
- if (event.pos.y < this.blueMap.element.offsetHeight / 3){
- this.element.addClass("below");
- } else {
- this.element.removeClass("below");
- }
- this.element.fadeIn(200);
-
+ //add block marker
if (hiresData){
this.blockMarker.position.set(block.x, block.y, block.z);
this.blueMap.hiresScene.add(this.blockMarker);
- this.blueMap.updateFrame = true;
+ this.blockMarker.needsUpdate = true;
}
+
+ this.showInfoBubble(content.html(), block.x + 0.5, block.y + 1, block.z + 0.5);
}
};
onHideInfo = event => {
- if (!this.element.is(':animated')) {
- this.element.fadeOut(200);
+ if (!this.bubble.is(':animated')) {
+ this.bubble.fadeOut(200, () => {
+ this.blueMap.hudScene.remove(this.hudElement);
+
+ if (this.onClose){
+ this.onClose();
+ this.onClose = undefined;
+ }
+ });
this.blueMap.hiresScene.remove(this.blockMarker);
this.blueMap.updateFrame = true;
}
diff --git a/BlueMapCore/src/main/webroot/js/libs/hud/Marker.js b/BlueMapCore/src/main/webroot/js/libs/hud/Marker.js
new file mode 100644
index 00000000..a0486a17
--- /dev/null
+++ b/BlueMapCore/src/main/webroot/js/libs/hud/Marker.js
@@ -0,0 +1,36 @@
+export default class Marker {
+
+ constructor(blueMap, markerSet, markerData) {
+ this.blueMap = blueMap;
+ this.markerSet = markerSet;
+ this.type = markerData.type;
+ this.map = markerData.map;
+ this.label = markerData.label;
+ this.link = markerData.link;
+ this.newTab = !!markerData.newTab;
+
+ this.visible = false;
+
+ this.minDistance = parseFloat(markerData.minDistance ? markerData.minDistance : 0);
+ this.minDistanceSquared = this.minDistance * this.minDistance;
+ this.maxDistance = parseFloat(markerData.maxDistance ? markerData.maxDistance : 100000);
+ this.maxDistanceSquared = this.maxDistance * this.maxDistance;
+ }
+
+ setVisible(visible) {
+ this.visible = visible && this.blueMap.map === this.map;
+ this.blueMap.updateFrame = true;
+ }
+
+ updateRenderObject(object, scene, camera){
+ if (this.visible) {
+ //update visiblity
+ let distanceSquared = object.position.distanceToSquared(camera.position);
+ object.visible = distanceSquared <= this.maxDistanceSquared && distanceSquared >= this.minDistanceSquared;
+ } else {
+ object.visible = false;
+ scene.remove(object);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/BlueMapCore/src/main/webroot/js/libs/hud/MarkerManager.js b/BlueMapCore/src/main/webroot/js/libs/hud/MarkerManager.js
new file mode 100644
index 00000000..b04621a9
--- /dev/null
+++ b/BlueMapCore/src/main/webroot/js/libs/hud/MarkerManager.js
@@ -0,0 +1,76 @@
+import MarkerSet from "./MarkerSet";
+import $ from "jquery";
+import ToggleButton from "../ui/ToggleButton";
+import Label from "../ui/Label";
+
+export default class MarkerManager {
+
+ constructor(blueMap, ui) {
+ this.blueMap = blueMap;
+ this.ui = ui;
+
+ this.markerSets = [];
+
+ this.readyPromise =
+ this.loadMarkerData()
+ .then(this.loadMarkers);
+
+ $(document).on('bluemap-map-change', this.onBlueMapMapChange);
+ }
+
+ loadMarkerData() {
+ return new Promise((resolve, reject) => {
+ this.blueMap.fileLoader.load(this.blueMap.dataRoot + 'markers.json',
+ markerData => {
+ this.markerData = JSON.parse(markerData);
+ resolve();
+ },
+ xhr => {},
+ error => {
+ reject();
+ }
+ );
+ });
+ }
+
+ loadMarkers = () => {
+ this.markerData.markerSets.forEach(setData => {
+ this.markerSets.push(new MarkerSet(this.blueMap, setData));
+ });
+ };
+
+ update(){
+ this.markerSets.forEach(markerSet => {
+ markerSet.update();
+ });
+ }
+
+ addMenuElements(menu){
+ let addedLabel = false;
+ this.markerSets.forEach(markerSet => {
+ if (markerSet.toggleable) {
+ if (!addedLabel){
+ menu.addElement(new Label("marker:"));
+ addedLabel = true;
+ }
+
+ let menuElement = new ToggleButton(markerSet.label, !markerSet.defaultHide, button => {
+ markerSet.visible = button.isSelected();
+ markerSet.update();
+ });
+
+ markerSet.visible = !markerSet.defaultHide;
+ markerSet.update();
+
+ menu.addElement(menuElement);
+ }
+ });
+ }
+
+ onBlueMapMapChange = async () => {
+ await this.readyPromise;
+
+ this.update();
+ };
+
+}
\ No newline at end of file
diff --git a/BlueMapCore/src/main/webroot/js/libs/hud/MarkerSet.js b/BlueMapCore/src/main/webroot/js/libs/hud/MarkerSet.js
new file mode 100644
index 00000000..aec4becc
--- /dev/null
+++ b/BlueMapCore/src/main/webroot/js/libs/hud/MarkerSet.js
@@ -0,0 +1,36 @@
+import POIMarker from "./POIMarker";
+import ShapeMarker from "./ShapeMarker";
+
+export default class MarkerSet {
+
+ constructor(blueMap, setData) {
+ this.blueMap = blueMap;
+ this.id = setData.id;
+ this.label = setData.label ? setData.label : this.id;
+ this.toggleable = setData.toggleable !== undefined ? !!setData.toggleable : true;
+ this.defaultHide = !!setData.defaultHide;
+ this.marker = [];
+
+ this.visible = true;
+
+ if (Array.isArray(setData.marker)){
+ setData.marker.forEach(markerData => {
+ switch (markerData.type){
+ case 'poi':
+ this.marker.push(new POIMarker(this.blueMap, this, markerData));
+ break;
+ case 'shape':
+ this.marker.push(new ShapeMarker(this.blueMap, this, markerData));
+ break;
+ }
+ });
+ }
+ }
+
+ update() {
+ this.marker.forEach(marker => {
+ marker.setVisible(this.visible);
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/BlueMapCore/src/main/webroot/js/libs/hud/POIMarker.js b/BlueMapCore/src/main/webroot/js/libs/hud/POIMarker.js
new file mode 100644
index 00000000..c9e7d2e2
--- /dev/null
+++ b/BlueMapCore/src/main/webroot/js/libs/hud/POIMarker.js
@@ -0,0 +1,57 @@
+import $ from 'jquery';
+import Marker from "./Marker";
+import {CSS2DObject} from "./CSS2DRenderer";
+import {Vector3} from "three";
+
+import POI from "../../../assets/poi.svg";
+
+export default class POIMarker extends Marker {
+
+ constructor(blueMap, markerSet, markerData) {
+ super(blueMap, markerSet, markerData);
+
+ this.icon = markerData.icon ? markerData.icon : POI;
+ this.iconAnchor = {
+ x: markerData.iconAnchor.x,
+ y: markerData.iconAnchor.y
+ };
+
+ this.position = new Vector3(markerData.position.x, markerData.position.y, markerData.position.z);
+ }
+
+ setVisible(visible){
+ super.setVisible(visible);
+
+ if (!this.renderObject){
+ let iconElement = $(``);
+ iconElement.find("img").click(this.onClick);
+ this.renderObject = new CSS2DObject(iconElement[0]);
+ this.renderObject.position.copy(this.position);
+ this.renderObject.onBeforeRender = (renderer, scene, camera) => this.updateRenderObject(this.renderObject, scene, camera);
+ }
+
+ if (this.visible) {
+ this.blueMap.hudScene.add(this.renderObject);
+ } else {
+ this.blueMap.hudScene.remove(this.renderObject);
+ }
+ }
+
+ onClick = () => {
+ if (this.label) {
+ this.setVisible(false);
+ this.blueMap.ui.hudInfo.showInfoBubble(this.label, this.position.x, this.position.y, this.position.z, () => {
+ this.setVisible(this.markerSet.visible);
+ });
+ }
+
+ if (this.link){
+ if (this.newTab){
+ window.open(this.link, '_blank');
+ } else {
+ location.href = this.link;
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/BlueMapCore/src/main/webroot/js/libs/hud/ShapeMarker.js b/BlueMapCore/src/main/webroot/js/libs/hud/ShapeMarker.js
new file mode 100644
index 00000000..603f83e1
--- /dev/null
+++ b/BlueMapCore/src/main/webroot/js/libs/hud/ShapeMarker.js
@@ -0,0 +1,72 @@
+import {
+ Vector2,
+ Shape,
+ ExtrudeBufferGeometry,
+ MeshBasicMaterial,
+ Mesh,
+ Object3D,
+ DoubleSide
+} from 'three';
+import Marker from "./Marker";
+
+export default class ShapeMarker extends Marker {
+
+ constructor(blueMap, markerSet, markerData) {
+ super(blueMap, markerSet, markerData);
+
+ let points = [];
+ if (Array.isArray(markerData.shape)) {
+ markerData.shape.forEach(point => {
+ points.push(new Vector2(point.x, point.z));
+ });
+ }
+ this.floor = markerData.floor ? markerData.floor : 0;
+ this.ceiling = markerData.ceiling ? markerData.ceiling : 128;
+
+ let shape = new Shape(points);
+ let extrude = new ExtrudeBufferGeometry(shape, {
+ steps: 1,
+ depth: this.ceiling - this.floor,
+ bevelEnabled: false
+ });
+ extrude.rotateX(Math.PI * 0.5);
+ extrude.translate(0, this.ceiling, 0);
+ let material = new MeshBasicMaterial( {
+ color: 0xff0000,
+ opacity: 0.25,
+ transparent: true,
+ side: DoubleSide
+ } );
+
+ let extrudeMesh = new Mesh( extrude, material );
+
+ this.renderObject = new Object3D();
+ this.renderObject.add(extrudeMesh);
+ }
+
+ setVisible(visible){
+ super.setVisible(visible);
+
+ if (this.visible) {
+ console.log(this.renderObject);
+ this.blueMap.shapeScene.add(this.renderObject);
+ } else {
+ this.blueMap.shapeScene.remove(this.renderObject);
+ }
+ }
+
+ onClick = () => {
+ if (this.label) {
+ //this.blueMap.ui.hudInfo.showInfoBubble(this.label, this.position.x, this.position.y, this.position.z);
+ }
+
+ if (this.link){
+ if (this.newTab){
+ window.open(this.link, '_blank');
+ } else {
+ location.href = this.link;
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/BlueMapCore/src/main/webroot/js/libs/ui/UI.js b/BlueMapCore/src/main/webroot/js/libs/ui/UI.js
index 4a96b5c6..b8bb6ab8 100644
--- a/BlueMapCore/src/main/webroot/js/libs/ui/UI.js
+++ b/BlueMapCore/src/main/webroot/js/libs/ui/UI.js
@@ -38,7 +38,8 @@ import ToggleButton from "./ToggleButton";
import MapSelection from "./MapSeletion";
import NIGHT from '../../../assets/night.svg';
-import HudInfo from "../modules/HudInfo";
+import HudInfo from "../hud/HudInfo";
+import MarkerManager from "../hud/MarkerManager";
export default class UI {
@@ -55,10 +56,11 @@ export default class UI {
this.toolbar.element.appendTo(this.hud);
//modules
- this.hudInfo = new HudInfo(this.blueMap, this.element);
+ this.hudInfo = new HudInfo(this.blueMap);
+ this.markers = new MarkerManager(this.blueMap, this);
}
- load() {
+ async load() {
//elements
let menuButton = new MenuButton(this.menu);
let mapSelect = new MapSelection(this.blueMap);
@@ -108,7 +110,11 @@ export default class UI {
//menu
this.menu.addElement(nightButton);
- this.menu.addElement(mobSpawnOverlay);
+ //this.menu.addElement(mobSpawnOverlay);
+
+ await this.markers.readyPromise;
+ this.markers.addMenuElements(this.menu);
+
this.menu.addElement(new Separator());
this.menu.addElement(new Label('render quality:'));
this.menu.addElement(quality);
@@ -119,7 +125,6 @@ export default class UI {
this.menu.addElement(new Separator());
this.menu.addElement(debugInfo);
this.menu.update();
-
}
}
\ No newline at end of file
diff --git a/BlueMapCore/src/main/webroot/style/modules/hudInfo.scss b/BlueMapCore/src/main/webroot/style/modules/hudInfo.scss
index c3cc84d1..997cd8ca 100644
--- a/BlueMapCore/src/main/webroot/style/modules/hudInfo.scss
+++ b/BlueMapCore/src/main/webroot/style/modules/hudInfo.scss
@@ -1,18 +1,15 @@
-.bluemap-container .ui .hud-info {
- position: absolute;
+.bluemap-container .hud-info {
+ pointer-events: none;
+}
- transform: translate(-50%, calc(-100% - 1rem));
+.bluemap-container .hud-info .bubble {
+ transform: translate(0, calc(-50% - 0.5rem));
background-color: $normal_bg;
filter: drop-shadow(1px 1px 3px #0008);
- pointer-events: none;
white-space: nowrap;
- &.below {
- transform: translate(-50%, 1rem);
- }
-
.content {
position: relative;
@@ -67,23 +64,26 @@
content: '';
position: absolute;
- bottom: -1rem;
+ bottom: calc(-1rem + 1px);
left: calc(50% - 0.5rem);
width: 0;
height: 0;
- z-index: 0;
-
border: solid 0.5rem;
border-color: $normal_bg transparent transparent transparent;
}
}
+}
- &.below .content::after {
- top: -1rem;
+.bluemap-container .marker-poi {
+ pointer-events: none;
- border: solid 0.5rem;
- border-color: transparent transparent $normal_bg transparent;
+ > * {
+ pointer-events: auto;
+ }
+
+ > img {
+ filter: drop-shadow(1px 1px 3px #0008);
}
}
\ No newline at end of file
diff --git a/BlueMapCore/src/main/webroot/style/style.scss b/BlueMapCore/src/main/webroot/style/style.scss
index 4ef91e78..a7d2e851 100644
--- a/BlueMapCore/src/main/webroot/style/style.scss
+++ b/BlueMapCore/src/main/webroot/style/style.scss
@@ -31,19 +31,30 @@ html, body {
overflow: hidden;
- > .map-canvas {
+ > .map-canvas, .map-canvas-hud {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
+ }
+ > .map-canvas {
background-color: #000;
-
z-index: 0;
}
+ > .map-canvas-hud {
+ pointer-events: none;
+
+ z-index: 10;
+
+ > * {
+ pointer-events: auto;
+ }
+ }
+
> .ui {
display: flex;
align-items: stretch;
diff --git a/BlueMapCore/webpack.config.js b/BlueMapCore/webpack.config.js
index 63497397..9c696846 100644
--- a/BlueMapCore/webpack.config.js
+++ b/BlueMapCore/webpack.config.js
@@ -6,75 +6,75 @@ 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')
+const WORLD_DATA_PATH = path.resolve(__dirname, '../data/test-render')
module.exports = {
- mode: 'production',
- devtool: 'source-map',
- entry: {
- 'bluemap': path.resolve(WEBROOT_PATH, 'js/site.js'),
- },
- output: {
- path: BUILD_PATH,
- filename: 'js/[name].js',
- },
- devServer: {
- contentBase: WORLD_DATA_PATH,
- compress: true,
- port: 8080,
- hot: true,
- host: '0.0.0.0'
- },
- plugins: [
- new MiniCssExtractPlugin({
- filename: 'style/[name].css?[hash]',
- }),
- new HtmlWebpackPlugin({
- template: path.resolve(WEBROOT_PATH, 'index.html'),
- 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]' },
- },
- ],
- },
- ],
- },
+ mode: 'production',
+ devtool: 'source-map',
+ entry: {
+ 'bluemap': path.resolve(WEBROOT_PATH, 'js/site.js'),
+ },
+ output: {
+ path: BUILD_PATH,
+ filename: 'js/[name].js',
+ },
+ devServer: {
+ contentBase: WORLD_DATA_PATH,
+ compress: true,
+ port: 8080,
+ hot: true,
+ host: '0.0.0.0'
+ },
+ plugins: [
+ new MiniCssExtractPlugin({
+ filename: 'style/[name].css?[hash]',
+ }),
+ new HtmlWebpackPlugin({
+ template: path.resolve(WEBROOT_PATH, 'index.html'),
+ 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]' },
+ },
+ ],
+ },
+ ],
+ },
}