diff --git a/src/BlueMap.js b/src/BlueMap.js index 442056b..6cb5f08 100644 --- a/src/BlueMap.js +++ b/src/BlueMap.js @@ -36,12 +36,11 @@ export * from "./markers/ExtrudeMarker"; export * from "./markers/HtmlMarker"; export * from "./markers/LineMarker"; export * from "./markers/Marker"; -export * from "./markers/MarkerFileManager"; export * from "./markers/MarkerManager"; export * from "./markers/MarkerSet"; +export * from "./markers/PlayerMarkerSet"; export * from "./markers/ObjectMarker"; export * from "./markers/PlayerMarker"; -export * from "./markers/PlayerMarkerManager"; export * from "./markers/PoiMarker"; export * from "./markers/ShapeMarker"; diff --git a/src/markers/MarkerFileManager.js b/src/markers/MarkerFileManager.js deleted file mode 100644 index 533e877..0000000 --- a/src/markers/MarkerFileManager.js +++ /dev/null @@ -1,167 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * 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 {Scene} from "three"; -import {MarkerSet} from "./MarkerSet"; -import {ShapeMarker} from "./ShapeMarker"; -import {alert} from "../util/Utils"; -import {ExtrudeMarker} from "./ExtrudeMarker"; -import {LineMarker} from "./LineMarker"; -import {HtmlMarker} from "./HtmlMarker"; -import {PoiMarker} from "./PoiMarker"; -import {MarkerManager} from "./MarkerManager"; - -/** - * A manager for loading and updating markers from a markers.json file - */ -export class MarkerFileManager extends MarkerManager { - - /** - * @constructor - * @param markerScene {Scene} - The scene to which all markers will be added - * @param fileUrl {string} - The marker file from which this manager updates its markers - * @param mapId {string} - The mapId of the map for which the markers should be loaded - * @param events {EventTarget} - */ - constructor(markerScene, fileUrl, mapId, events = null) { - super(markerScene, fileUrl, events); - Object.defineProperty(this, 'isMarkerFileManager', {value: true}); - - this.mapId = mapId; - } - - updateFromData(markerData) { - if (!Array.isArray(markerData.markerSets)) return false; - let updatedMarkerSets = new Set(); - - // add & update - markerData.markerSets.forEach(markerSetData => { - try { - let markerSet = this.updateMarkerSetFromData(markerSetData); - updatedMarkerSets.add(markerSet); - } catch (err) { - alert(this.events, err, "fine"); - } - }); - - // remove not updated MarkerSets - this.markerSets.forEach((markerSet, setId) => { - if (!updatedMarkerSets.has(markerSet)) { - this.removeMarkerSet(setId); - } - }); - - return true; - } - - /** - * @private - * Updates a managed MarkerSet using the provided data - * @param markerSetData {object} - The data object for a MarkerSet, usually parsed json from a markers.json - * @returns {MarkerSet} - The updated MarkerSet - * @throws {Error} - On invalid / missing data - */ - updateMarkerSetFromData(markerSetData) { - if (!markerSetData.id) throw new Error("markerset-data has no id!"); - let markerSet = this.markerSets.get(markerSetData.id); - - // create new if not existent - if (!markerSet) { - markerSet = new MarkerSet(markerSetData.id); - this.addMarkerSet(markerSet); - - if (markerSetData.defaultHide) { - markerSet.visible = false; - } - } - - // update set info - markerSet.data.label = markerSetData.label || markerSetData.id; - markerSet.data.toggleable = !!markerSetData.toggleable; - markerSet.data.defaultHide = !!markerSetData.defaultHide; - - // update markers - let updatedMarkers = new Set(); - - if (Array.isArray(markerSetData.marker)) { - markerSetData.marker.forEach(markerData => { - if (markerData.map && markerData.map !== this.mapId) return; - - try { - let marker = this.updateMarkerFromData(markerSet, markerData); - updatedMarkers.add(marker); - } catch (err) { - alert(this.events, err, "fine"); - console.debug(err); - } - }); - } - - // remove not updated Markers - markerSet.children.forEach((marker) => { - if (marker.isMarker && !updatedMarkers.has(marker)) { - this.removeMarker(marker.data.id); - } - }); - - return markerSet; - } - - /** - * @private - * Updates a managed Marker using the provided data - * @param markerSet {MarkerSet} - The MarkerSet this marker should be in - * @param markerData {object} - * @returns {Marker} - The updated Marker - * @throws {Error} - On invalid / missing data - */ - updateMarkerFromData(markerSet, markerData) { - if (!markerData.id) throw new Error("marker-data has no id!"); - if (!markerData.type) throw new Error("marker-data has no type!"); - let marker = this.markers.get(markerData.id); - - // create new if not existent of wrong type - if (!marker || marker.data.type !== markerData.type) { - switch (markerData.type) { - case "shape" : marker = new ShapeMarker(markerData.id); break; - case "extrude" : marker = new ExtrudeMarker(markerData.id); break; - case "line" : marker = new LineMarker(markerData.id); break; - case "html" : marker = new HtmlMarker(markerData.id); break; - case "poi" : marker = new PoiMarker(markerData.id); break; - default : throw new Error(`Unknown marker-type: '${markerData.type}'`); - } - - this.addMarker(markerSet, marker); - } - - // make sure marker is in the correct MarkerSet - if (marker.parent !== markerSet) markerSet.add(marker); - - // update marker - marker.updateFromData(markerData); - - return marker; - } - -} \ No newline at end of file diff --git a/src/markers/MarkerManager.js b/src/markers/MarkerManager.js index 2b9ea55..22748d5 100644 --- a/src/markers/MarkerManager.js +++ b/src/markers/MarkerManager.js @@ -25,6 +25,14 @@ import {FileLoader, Scene} from "three"; import {MarkerSet} from "./MarkerSet"; import {alert, generateCacheHash} from "../util/Utils"; +import {PlayerMarkerSet} from "./PlayerMarkerSet"; + +export const MarkerFileType = { + NORMAL: 1, + PLAYER: 2, +} + +export const PLAYER_MARKER_SET_ID = "bm-players"; /** * A manager for loading and updating markers from a file @@ -33,22 +41,19 @@ export class MarkerManager { /** * @constructor - * @param markerScene {Scene} - The scene to which all markers will be added + * @param root {MarkerSet} - The scene to which all markers will be added * @param fileUrl {string} - The marker file from which this manager updates its markers + * @param fileType {number} - The type of the marker-file, see MarkerManager.NORMAL and MarkerManager.PLAYER * @param events {EventTarget} */ - constructor(markerScene, fileUrl, events = null) { + constructor(root, fileUrl, fileType, events = null) { Object.defineProperty(this, 'isMarkerManager', {value: true}); - this.markerScene = markerScene; + this.root = root; this.fileUrl = fileUrl; + this.fileType = fileType; this.events = events; - /** @type {Map} */ - this.markerSets = new Map(); - /** @type {Map} */ - this.markers = new Map(); - /** @type {NodeJS.Timeout} */ this._updateInterval = null; } @@ -89,83 +94,74 @@ export class MarkerManager { .then(markerFileData => this.updateFromData(markerFileData)); } + /** + * @private + * @param markerData + */ + updateFromData(markerData) { + switch (this.fileType) { + case MarkerFileType.NORMAL: return this.updateFromDataNormal(markerData); + case MarkerFileType.PLAYER: return this.updateFromDataPlayer(markerData); + } + } + + /** + * @private + * @param markerData + * @returns {boolean} + */ + updateFromDataNormal(markerData) { + this.root.updateMarkerSetsFromData(markerData, [PLAYER_MARKER_SET_ID, "bm-popup-set"]); + return true; + } + + /** + * @private + * @param markerFileData + * @returns {boolean} + */ + updateFromDataPlayer(markerFileData) { + let playerMarkerSet = this.getPlayerMarkerSet(); + return playerMarkerSet.updateFromPlayerData(markerFileData); + } + + /** + * @private + * @returns {PlayerMarkerSet} + */ + getPlayerMarkerSet() { + /** @type {PlayerMarkerSet} */ + let playerMarkerSet = /** @type {PlayerMarkerSet} */ this.root.markerSets.get(PLAYER_MARKER_SET_ID); + + if (!playerMarkerSet) { + playerMarkerSet = new PlayerMarkerSet(PLAYER_MARKER_SET_ID); + this.root.add(playerMarkerSet); + } + + return playerMarkerSet; + } + + /** + * @param playerUuid {string} + * @returns {PlayerMarker | undefined} + */ + getPlayerMarker(playerUuid) { + return this.getPlayerMarkerSet().getPlayerMarker(playerUuid) + } + /** * Stops automatic-updates and disposes all markersets and markers managed by this manager */ dispose() { this.setAutoUpdateInterval(0); - this.markerSets.forEach(markerSet => markerSet.dispose()); + this.clear(); } /** * Removes all markers managed by this marker-manager */ clear() { - this.markerSets.forEach(markerSet => this.removeMarkerSet(markerSet.data.id)); - } - - /** - * @protected - * Adds a MarkerSet to this Manager, removing any existing markerSet with this id first. - * @param markerSet {MarkerSet} - */ - addMarkerSet(markerSet) { - this.removeMarkerSet(markerSet.data.id); - - this.markerSets.set(markerSet.data.id, markerSet); - this.markerScene.add(markerSet); - } - - /** - * @protected - * Removes a MarkerSet from this Manager - * @param setId {string} - The id of the MarkerSet - */ - removeMarkerSet(setId) { - let markerSet = this.markerSets.get(setId); - - if (markerSet) { - this.markerScene.remove(markerSet); - this.markerSets.delete(setId); - markerSet.dispose(); - } - } - - /** - * @protected - * Adds a marker to this manager - * @param markerSet {MarkerSet} - * @param marker {Marker} - */ - addMarker(markerSet, marker) { - this.removeMarker(marker.data.id); - - this.markers.set(marker.data.id, marker); - markerSet.add(marker); - } - - /** - * @protected - * Removes a marker from this manager - * @param markerId {string} - */ - removeMarker(markerId) { - let marker = this.markers.get(markerId); - - if (marker) { - if (marker.parent) marker.parent.remove(marker); - this.markers.delete(markerId); - marker.dispose(); - } - } - - /** - * Updates all managed markers using the provided data. - * @param markerData {object} - The data object, usually parsed json from a markers.json - * @returns {boolean} - If the update was successful - */ - updateFromData(markerData) { - return false; + this.root.clear(); } /** diff --git a/src/markers/MarkerSet.js b/src/markers/MarkerSet.js index 3221a7c..6e617c2 100644 --- a/src/markers/MarkerSet.js +++ b/src/markers/MarkerSet.js @@ -23,6 +23,12 @@ * THE SOFTWARE. */ import {Scene} from "three"; +import {alert} from "../util/Utils"; +import {ShapeMarker} from "./ShapeMarker"; +import {ExtrudeMarker} from "./ExtrudeMarker"; +import {LineMarker} from "./LineMarker"; +import {HtmlMarker} from "./HtmlMarker"; +import {PoiMarker} from "./PoiMarker"; export class MarkerSet extends Scene { @@ -33,6 +39,11 @@ export class MarkerSet extends Scene { super(); Object.defineProperty(this, 'isMarkerSet', {value: true}); + /** @type {Map} */ + this.markerSets = new Map(); + /** @type {Map} */ + this.markers = new Map(); + this.data = { id: id, label: id, @@ -49,13 +60,125 @@ export class MarkerSet extends Scene { }); } + updateFromData(data) { + // update set info + this.data.label = data.label || this.data.id; + this.data.toggleable = !!data.toggleable; + this.data.defaultHide = !!data.defaultHidden; + + // update markerSets + this.updateMarkerSetsFromData(data.markerSets); + + // update markers + this.updateMarkersFromData(data.markers); + } + + updateMarkerSetsFromData(data = {}, ignore = []) { + let updatedMarkerSets = new Set(ignore); + + // add & update MarkerSets + Object.keys(data).forEach(markerSetId => { + if (updatedMarkerSets.has(markerSetId)) return; + + let markerSetData = data[markerSetId]; + try { + this.updateMarkerSetFromData(markerSetId, markerSetData); + updatedMarkerSets.add(markerSetId); + } catch (err) { + alert(this.events, err, "fine"); + } + }); + + // remove not updated MarkerSets + this.markerSets.forEach((markerSet, setId) => { + if (!updatedMarkerSets.has(setId)) { + this.remove(markerSet); + } + }); + } + + updateMarkerSetFromData(markerSetId, data) { + let markerSet = this.markerSets.get(markerSetId); + + // create new if not existent + if (!markerSet) { + markerSet = new MarkerSet(markerSetId); + this.add(markerSet); + + if (data.defaultHide) { + markerSet.visible = false; + } + } + + // update + markerSet.updateFromData(data); + } + + updateMarkersFromData(data = {}, ignore = []) { + let updatedMarkers = new Set(ignore); + + Object.keys(data).forEach(markerId => { + if (updatedMarkers.has(markerId)) return; + + let markerData = data[markerId]; + try { + this.updateMarkerFromData(markerId, markerData); + updatedMarkers.add(markerId); + } catch (err) { + alert(this.events, err, "fine"); + console.debug(err); + } + }); + + // remove not updated Markers + this.markers.forEach((marker, markerId) => { + if (!updatedMarkers.has(markerId)) { + this.remove(marker); + } + }); + } + + updateMarkerFromData(markerId, data) { + if (!data.type) throw new Error("marker-data has no type!"); + let marker = this.markers.get(markerId); + + // create new if not existent of wrong type + if (!marker || marker.data.type !== data.type) { + if (marker) this.remove(marker); + + switch (data.type) { + case "shape" : marker = new ShapeMarker(markerId); break; + case "extrude" : marker = new ExtrudeMarker(markerId); break; + case "line" : marker = new LineMarker(markerId); break; + case "html" : marker = new HtmlMarker(markerId); break; + case "poi" : marker = new PoiMarker(markerId); break; + default : throw new Error(`Unknown marker-type: '${data.type}'`); + } + + this.add(marker); + } + + // update marker + marker.updateFromData(data); + } + + /** + * Removes all markers and marker-sets + */ + clear() { + [...this.data.markerSets].forEach(markerSet => this.remove(markerSet)); + [...this.data.markers].forEach(marker => this.remove(marker)); + } + add(...object) { - if (object.length === 1) { //super.add() will re-invoke this method for each array-entry if its more than one + if (object.length === 1) { //super.add() will re-invoke this method for each array-entry if it's more than one let o = object[0]; - if (o.isMarkerSet) { + if (o.isMarkerSet && !this.markerSets.has(o.data.id)) { + this.markerSets.set(o.data.id, o); this.data.markerSets.push(o.data); } - if (o.isMarker) { + if (o.isMarker && !this.markers.has(o.data.id)) { + this.markers.set(o.data.id, o); this.data.markers.push(o.data); } } @@ -64,15 +187,19 @@ export class MarkerSet extends Scene { } remove(...object) { - if (object.length === 1) { //super.remove() will re-invoke this method for each array-entry if its more than one + if (object.length === 1) { //super.remove() will re-invoke this method for each array-entry if it's more than one let o = object[0]; if (o.isMarkerSet) { let i = this.data.markerSets.indexOf(o.data); if (i > -1) this.data.markerSets.splice(i, 1); + this.markerSets.delete(o.data.id); + o.dispose(); } if (o.isMarker) { let i = this.data.markers.indexOf(o.data); if (i > -1) this.data.markers.splice(i, 1); + this.markers.delete(o.data.id); + o.dispose(); } } diff --git a/src/markers/PlayerMarkerManager.js b/src/markers/PlayerMarkerSet.js similarity index 59% rename from src/markers/PlayerMarkerManager.js rename to src/markers/PlayerMarkerSet.js index da2d1c5..9706737 100644 --- a/src/markers/PlayerMarkerManager.js +++ b/src/markers/PlayerMarkerSet.js @@ -22,32 +22,22 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -import {MarkerManager} from "./MarkerManager"; -import {alert} from "../util/Utils"; + import {MarkerSet} from "./MarkerSet"; +import {alert} from "../util/Utils"; import {PlayerMarker} from "./PlayerMarker"; -export class PlayerMarkerManager extends MarkerManager { +export class PlayerMarkerSet extends MarkerSet { - /** - * @constructor - * @param markerScene {THREE.Scene} - The scene to which all markers will be added - * @param playerDataUrl {string} - The marker file from which this manager updates its markers - * @param events {EventTarget} - */ - constructor(markerScene, playerDataUrl, events = null) { - super(markerScene, playerDataUrl, events); - Object.defineProperty(this, 'isPlayerMarkerManager', {value: true}); - - this.getPlayerMarkerSet(); + constructor(id) { + super(id); + this.data.label = "Player"; + this.data.toggleable = true; + this.data.defaultHide = false; } - /** - * @param markerData {{players: PlayerLike[]}} - */ - updateFromData(markerData) { - - if (!Array.isArray(markerData.players)) { + updateFromPlayerData(data) { + if (!Array.isArray(data.players)) { this.clear(); return false; } @@ -56,7 +46,7 @@ export class PlayerMarkerManager extends MarkerManager { let updatedPlayerMarkers = new Set(); // update - markerData.players.forEach(playerData => { + data.players.forEach(playerData => { try { let playerMarker = this.updatePlayerMarkerFromData(playerData); updatedPlayerMarkers.add(playerMarker); @@ -66,39 +56,30 @@ export class PlayerMarkerManager extends MarkerManager { }); // remove - this.markers.forEach((playerMarker, markerId) => { + this.markers.forEach(playerMarker => { if (!updatedPlayerMarkers.has(playerMarker)) { - this.removeMarker(markerId); + this.remove(playerMarker); } }); return true; } - /** - * @private - * @param markerData {PlayerLike} - * @returns PlayerMarker - */ updatePlayerMarkerFromData(markerData) { let playerUuid = markerData.uuid; if (!playerUuid) throw new Error("player-data has no uuid!"); - let markerId = "bm-player-" + playerUuid; + let markerId = this.getPlayerMarkerId(playerUuid); /** @type PlayerMarker */ let marker = this.markers.get(markerId); - let markerSet = this.getPlayerMarkerSet(); - // create new if not existent of wrong type if (!marker || !marker.isPlayerMarker) { + if (marker) this.remove(marker); marker = new PlayerMarker(markerId, playerUuid); - this.addMarker(markerSet, marker); + this.add(marker); } - // make sure marker is in the correct MarkerSet - if (marker.parent !== markerSet) markerSet.add(marker); - // update marker.updateFromData(markerData); @@ -108,28 +89,12 @@ export class PlayerMarkerManager extends MarkerManager { return marker; } - /** - * @private - * @returns {MarkerSet} - */ - getPlayerMarkerSet() { - let playerMarkerSet = this.markerSets.get("bm-players"); - - if (!playerMarkerSet) { - playerMarkerSet = new MarkerSet("bm-players"); - playerMarkerSet.data.label = "Players"; - this.addMarkerSet(playerMarkerSet); - } - - return playerMarkerSet; + getPlayerMarker(playerUuid) { + return this.markers.get(this.getPlayerMarkerId(playerUuid)); } - /** - * @param playerUuid {string} - * @returns {Marker} - */ - getPlayerMarker(playerUuid) { - return this.markers.get("bm-player-" + playerUuid); + getPlayerMarkerId(playerUuid) { + return "bm-player-" + playerUuid; } } \ No newline at end of file