forked from Garde-Studios/minecraft-docker-server
Changed: Squaremap configs support LiveAtlas & Squaremap Markers
This commit is contained in:
11
main/squaremap/web/js/modules/util/Fieldset.js
Normal file
11
main/squaremap/web/js/modules/util/Fieldset.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { P } from '../Squaremap.js';
|
||||
|
||||
class Fieldset {
|
||||
constructor(id, title) {
|
||||
this.element = P.createElement("fieldset", id);
|
||||
this.legend = P.createTextElement("legend", title);
|
||||
this.element.appendChild(this.legend);
|
||||
}
|
||||
}
|
||||
|
||||
export { Fieldset };
|
163
main/squaremap/web/js/modules/util/Markers.js
Normal file
163
main/squaremap/web/js/modules/util/Markers.js
Normal file
@@ -0,0 +1,163 @@
|
||||
import { P } from '../Squaremap.js';
|
||||
|
||||
class Marker {
|
||||
constructor(opts) {
|
||||
this.opts = opts;
|
||||
this.id = this.opts.pop("id");
|
||||
this.popup = this.opts.pop("popup");
|
||||
this.popup_sticky = true;
|
||||
this.tooltip = this.opts.pop("tooltip");
|
||||
this.tooltip_sticky = true;
|
||||
}
|
||||
init() {
|
||||
if (this.popup != null) {
|
||||
if (this.popup_sticky) {
|
||||
this.marker.on('click', (e) => {
|
||||
L.popup({
|
||||
direction: this.opts.pop("tooltip_direction", "top")
|
||||
})
|
||||
.setLatLng(P.toLatLng(P.coordinates.coords.x, P.coordinates.coords.z))
|
||||
.setContent(this.popup)
|
||||
.openOn(P.map);
|
||||
});
|
||||
} else {
|
||||
this.marker.bindPopup(() => this.popup, {
|
||||
direction: this.opts.pop("tooltip_direction", "top")
|
||||
});
|
||||
}
|
||||
}
|
||||
if (this.tooltip != null) {
|
||||
this.marker.bindTooltip(() => this.tooltip, {
|
||||
direction: this.opts.pop("tooltip_direction", "top"),
|
||||
sticky: this.tooltip_sticky
|
||||
});
|
||||
}
|
||||
for (const key in this.opts) {
|
||||
this.marker.options[key] = this.opts[key];
|
||||
}
|
||||
}
|
||||
addTo(layer) {
|
||||
this.marker.remove();
|
||||
this.marker.addTo(layer);
|
||||
}
|
||||
}
|
||||
|
||||
class Options {
|
||||
constructor(json) {
|
||||
for (const prop in json) {
|
||||
this[prop] = json[prop];
|
||||
}
|
||||
}
|
||||
pop(key, def) {
|
||||
const val = this[key];
|
||||
delete this[key];
|
||||
return val == null ? def : val;
|
||||
}
|
||||
}
|
||||
|
||||
class Rectangle extends Marker {
|
||||
constructor(opts) {
|
||||
super(opts);
|
||||
const points = this.opts.pop("points");
|
||||
this.marker = L.rectangle([P.toLatLng(points[0].x, points[0].z), P.toLatLng(points[1].x, points[1].z)]);
|
||||
super.init();
|
||||
}
|
||||
}
|
||||
|
||||
class PolyLine extends Marker {
|
||||
constructor(opts) {
|
||||
super(opts);
|
||||
const points = this.opts.pop("points");
|
||||
const outer = [];
|
||||
for (let i = 0; i < points.length; i++) {
|
||||
if (Symbol.iterator in Object(points[i])) {
|
||||
const inner = [];
|
||||
for (let j = 0; j < points[i].length; j++) {
|
||||
inner.push(P.toLatLng(points[i][j].x, points[i][j].z));
|
||||
}
|
||||
outer.push(inner);
|
||||
} else {
|
||||
outer.push(P.toLatLng(points[i].x, points[i].z));
|
||||
}
|
||||
}
|
||||
this.marker = L.polyline(outer);
|
||||
super.init();
|
||||
}
|
||||
}
|
||||
|
||||
class Polygon extends Marker {
|
||||
constructor(opts) {
|
||||
super(opts);
|
||||
const points = this.opts.pop("points");
|
||||
const outer = [];
|
||||
for (let i = 0; i < points.length; i++) {
|
||||
if (Symbol.iterator in Object(points[i])) {
|
||||
const inner = [];
|
||||
for (let j = 0; j < points[i].length; j++) {
|
||||
if (Symbol.iterator in Object(points[i][j])) {
|
||||
const inner2 = [];
|
||||
for (let k = 0; k < points[i][j].length; k++) {
|
||||
inner2.push(P.toLatLng(points[i][j][k].x, points[i][j][k].z));
|
||||
}
|
||||
inner.push(inner2);
|
||||
} else {
|
||||
inner.push(P.toLatLng(points[i][j].x, points[i][j].z));
|
||||
}
|
||||
}
|
||||
outer.push(inner);
|
||||
} else {
|
||||
outer.push(P.toLatLng(points[i].x, points[i].z));
|
||||
}
|
||||
}
|
||||
this.marker = L.polygon(outer);
|
||||
super.init();
|
||||
}
|
||||
}
|
||||
|
||||
class Circle extends Marker {
|
||||
constructor(opts) {
|
||||
super(opts);
|
||||
const center = this.opts.pop("center");
|
||||
const radius = this.opts.pop("radius");
|
||||
this.marker = L.circle(P.toLatLng(center.x, center.z), {
|
||||
radius: P.pixelsToMeters(radius)
|
||||
});
|
||||
super.init();
|
||||
}
|
||||
}
|
||||
|
||||
class Ellipse extends Marker {
|
||||
constructor(opts) {
|
||||
super(opts);
|
||||
const center = this.opts.pop("center");
|
||||
const radiusX = this.opts.pop("radiusX");
|
||||
const radiusZ = this.opts.pop("radiusZ");
|
||||
const tilt = 0;
|
||||
this.marker = L.ellipse(P.toLatLng(center.x, center.z), [radiusX, radiusZ], tilt);
|
||||
super.init();
|
||||
}
|
||||
}
|
||||
|
||||
class Icon extends Marker {
|
||||
constructor(opts) {
|
||||
super(opts);
|
||||
const point = this.opts.pop("point");
|
||||
const size = this.opts.pop("size");
|
||||
const anchor = this.opts.pop("anchor");
|
||||
const tooltipAnchor = this.opts.pop("tooltip_anchor", L.point(0, -size.z / 2));
|
||||
this.marker = L.marker(P.toLatLng(point.x, point.z), {
|
||||
icon: L.icon({
|
||||
iconUrl: `images/icon/registered/${opts.pop("icon")}.png`,
|
||||
iconSize: [size.x, size.z],
|
||||
iconAnchor: [anchor.x, anchor.z],
|
||||
popupAnchor: [tooltipAnchor.x, tooltipAnchor.z],
|
||||
tooltipAnchor: [tooltipAnchor.x, tooltipAnchor.z]
|
||||
})
|
||||
});
|
||||
this.popup_sticky = false;
|
||||
this.tooltip_sticky = false;
|
||||
super.init();
|
||||
}
|
||||
}
|
||||
|
||||
export { Marker, Options, Rectangle, PolyLine, Polygon, Circle, Ellipse, Icon };
|
23
main/squaremap/web/js/modules/util/Pin.js
Normal file
23
main/squaremap/web/js/modules/util/Pin.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { P } from '../Squaremap.js';
|
||||
|
||||
class Pin {
|
||||
constructor(def) {
|
||||
this.pinned = def;
|
||||
|
||||
this.element = P.createElement("img", "pin", this);
|
||||
|
||||
this.element.onclick = () => this.toggle();
|
||||
|
||||
this.pin(this.pinned);
|
||||
}
|
||||
toggle() {
|
||||
this.pin(!this.pinned);
|
||||
}
|
||||
pin(pin) {
|
||||
this.pinned = pin;
|
||||
this.element.className = pin ? "pinned" : "unpinned";
|
||||
this.element.src = `images/${this.element.className}.png`;
|
||||
}
|
||||
}
|
||||
|
||||
export { Pin };
|
98
main/squaremap/web/js/modules/util/Player.js
Normal file
98
main/squaremap/web/js/modules/util/Player.js
Normal file
@@ -0,0 +1,98 @@
|
||||
import { P } from '../Squaremap.js';
|
||||
|
||||
class Player {
|
||||
constructor(json) {
|
||||
this.name = json.name;
|
||||
this.uuid = json.uuid;
|
||||
this.world = json.world;
|
||||
this.displayName = json.display_name !== undefined ? json.display_name : json.name;
|
||||
this.x = 0;
|
||||
this.z = 0;
|
||||
this.armor = 0;
|
||||
this.health = 20;
|
||||
this.tooltip = L.tooltip({
|
||||
permanent: true,
|
||||
direction: "right",
|
||||
offset: [10, 0],
|
||||
pane: "nameplate"
|
||||
});
|
||||
this.marker = L.marker(P.toLatLng(json.x, json.z), {
|
||||
icon: L.icon({
|
||||
iconUrl: 'images/icon/player.png',
|
||||
iconSize: [17, 16],
|
||||
iconAnchor: [8, 9],
|
||||
tooltipAnchor: [0, 0]
|
||||
}),
|
||||
rotationAngle: (180 + json.yaw)
|
||||
});
|
||||
if (P.worldList.curWorld.player_tracker.nameplates.enabled) {
|
||||
this.updateNameplate(json);
|
||||
this.marker.bindTooltip(this.tooltip);
|
||||
}
|
||||
}
|
||||
getHeadUrl() {
|
||||
return P.worldList.curWorld.player_tracker.nameplates.heads_url
|
||||
.replace(/{uuid}/g, this.uuid)
|
||||
.replace(/{name}/g, this.name);
|
||||
}
|
||||
updateNameplate(player) {
|
||||
let headImg = "";
|
||||
let armorImg = "";
|
||||
let healthImg = "";
|
||||
if (P.worldList.curWorld.player_tracker.nameplates.show_heads) {
|
||||
headImg = `<img src='${this.getHeadUrl()}' class="head" />`;
|
||||
}
|
||||
if (P.worldList.curWorld.player_tracker.nameplates.show_armor && player.armor != null) {
|
||||
armorImg = `<img src="images/armor/${Math.min(Math.max(player.armor, 0), 20)}.png" class="armor" />`;
|
||||
}
|
||||
if (P.worldList.curWorld.player_tracker.nameplates.show_health && player.health != null) {
|
||||
healthImg = `<img src="images/health/${Math.min(Math.max(player.health, 0), 20)}.png" class="health" />`;
|
||||
}
|
||||
this.tooltip.setContent(`<ul><li>${headImg}</li><li>${this.displayName}${healthImg}${armorImg}</li>`);
|
||||
}
|
||||
update(player) {
|
||||
this.x = player.x;
|
||||
this.z = player.z;
|
||||
this.world = player.world;
|
||||
this.armor = player.armor;
|
||||
this.health = player.health;
|
||||
this.displayName = player.display_name !== undefined ? player.display_name : player.name;
|
||||
const link = document.getElementById(player.uuid);
|
||||
const img = link.getElementsByTagName("img")[0];
|
||||
const span = link.getElementsByTagName("span")[0];
|
||||
if (P.worldList.curWorld.name == player.world) {
|
||||
if (P.worldList.curWorld.player_tracker.enabled) {
|
||||
this.addMarker();
|
||||
}
|
||||
const latlng = P.toLatLng(player.x, player.z);
|
||||
if (!this.marker.getLatLng().equals(latlng)) {
|
||||
this.marker.setLatLng(latlng);
|
||||
}
|
||||
const angle = 180 + player.yaw;
|
||||
if (this.marker.options.rotationAngle != angle) {
|
||||
this.marker.setRotationAngle(angle);
|
||||
}
|
||||
img.classList.remove("other-world");
|
||||
span.classList.remove("other-world");
|
||||
} else {
|
||||
this.removeMarker();
|
||||
img.classList.add("other-world");
|
||||
span.classList.add("other-world");
|
||||
}
|
||||
this.updateNameplate(player);
|
||||
}
|
||||
removeMarker() {
|
||||
this.marker.remove();
|
||||
P.playerList.markers.delete(this.uuid);
|
||||
P.map.removeLayer(this.marker);
|
||||
P.layerControl.playersLayer.removeLayer(this.marker);
|
||||
}
|
||||
addMarker() {
|
||||
if (!P.playerList.markers.has(this.uuid)) {
|
||||
this.marker.addTo(P.layerControl.playersLayer);
|
||||
P.playerList.markers.set(this.uuid, this.marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { Player };
|
145
main/squaremap/web/js/modules/util/World.js
Normal file
145
main/squaremap/web/js/modules/util/World.js
Normal file
@@ -0,0 +1,145 @@
|
||||
import { Options, Rectangle, PolyLine, Polygon, Circle, Ellipse, Icon } from "./Markers.js";
|
||||
import { P } from '../Squaremap.js';
|
||||
|
||||
class World {
|
||||
constructor(json) {
|
||||
this.name = json.name;
|
||||
this.order = json.order;
|
||||
this.icon = json.icon;
|
||||
this.type = json.type;
|
||||
this.display_name = json.display_name;
|
||||
this.markerLayers = new Map();
|
||||
this.player_tracker = {};
|
||||
this.marker_update_interval = 5;
|
||||
this.tiles_update_interval = 15;
|
||||
}
|
||||
tick() {
|
||||
// refresh map tile layer
|
||||
if (P.tick_count % this.tiles_update_interval == 0) {
|
||||
P.layerControl.updateTileLayer();
|
||||
}
|
||||
// load and draw markers
|
||||
if (P.tick_count % this.marker_update_interval == 0) {
|
||||
P.getJSON(`tiles/${this.name}/markers.json`, (json) => {
|
||||
if (this === P.worldList.curWorld) {
|
||||
this.markers(json);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
unload() {
|
||||
P.playerList.clearPlayerMarkers();
|
||||
const keys = Array.from(this.markerLayers.keys());
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const layer = this.markerLayers.get(keys[i]);
|
||||
P.layerControl.controls.removeLayer(layer);
|
||||
layer.remove();
|
||||
this.markerLayers.delete(keys[i]);
|
||||
}
|
||||
}
|
||||
load(callback) {
|
||||
P.getJSON(`tiles/${this.name}/settings.json`, (json) => {
|
||||
this.player_tracker = json.player_tracker;
|
||||
this.zoom = json.zoom;
|
||||
this.spawn = json.spawn;
|
||||
this.marker_update_interval = json.marker_update_interval;
|
||||
this.tiles_update_interval = json.tiles_update_interval;
|
||||
|
||||
// set the scale for our projection calculations
|
||||
P.setScale(this.zoom.max);
|
||||
|
||||
// set center and zoom
|
||||
P.centerOn(this.spawn.x, this.spawn.z, this.zoom.def)
|
||||
.setMinZoom(0) // extra zoom out doesn't work :(
|
||||
.setMaxZoom(this.zoom.max + this.zoom.extra);
|
||||
|
||||
// update page title
|
||||
document.title = P.title
|
||||
.replace(/{world}/g, this.display_name);
|
||||
|
||||
// setup background
|
||||
document.getElementById("map").style.background = this.getBackground();
|
||||
|
||||
// setup tile layers
|
||||
P.layerControl.setupTileLayers(this);
|
||||
|
||||
// force clear player markers
|
||||
P.playerList.clearPlayerMarkers();
|
||||
|
||||
// tick now, reset counter
|
||||
P.tick_count = 0;
|
||||
P.tick();
|
||||
|
||||
// force clear player markers
|
||||
P.playerList.clearPlayerMarkers();
|
||||
|
||||
if (callback != null) {
|
||||
callback(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
getBackground() {
|
||||
switch (this.type) {
|
||||
case "nether":
|
||||
return "url('images/nether_sky.png')";
|
||||
case "the_end":
|
||||
return "url('images/end_sky.png')";
|
||||
case "normal":
|
||||
default:
|
||||
return "url('images/overworld_sky.png')";
|
||||
}
|
||||
}
|
||||
markers(json) {
|
||||
// check if json is iterable
|
||||
if (json == null || !(Symbol.iterator in Object(json))) {
|
||||
return;
|
||||
}
|
||||
// iterate layers
|
||||
for (const entry of json) {
|
||||
// check if layer exists and needs updating
|
||||
let layer = this.markerLayers.get(entry.id);
|
||||
if (layer != null) {
|
||||
if (layer.timestamp === entry.timestamp) {
|
||||
continue; // skip
|
||||
}
|
||||
// clear existing layer to rebuild
|
||||
P.layerControl.removeOverlay(layer);
|
||||
// TODO
|
||||
// implement marker tracker instead of clearing
|
||||
// to reduce possible client side lag
|
||||
}
|
||||
|
||||
// setup the layer
|
||||
layer = new L.LayerGroup();
|
||||
layer.order = entry.order;
|
||||
layer.id = entry.id;
|
||||
layer.timestamp = entry.timestamp;
|
||||
layer.setZIndex(entry.z_index);
|
||||
this.markerLayers.set(layer.id, layer);
|
||||
|
||||
// setup the layer control
|
||||
if (entry.control === true) {
|
||||
P.layerControl.addOverlay(entry.name, layer, entry.hide);
|
||||
}
|
||||
|
||||
// setup the markers
|
||||
for (const shape in entry.markers) {
|
||||
let marker;
|
||||
const opts = new Options(entry.markers[shape]);
|
||||
switch(opts.pop("type")) {
|
||||
case "rectangle": marker = new Rectangle(opts); break;
|
||||
case "polyline": marker = new PolyLine(opts); break;
|
||||
case "polygon": marker = new Polygon(opts); break;
|
||||
case "circle": marker = new Circle(opts); break;
|
||||
case "ellipse": marker = new Ellipse(opts); break;
|
||||
case "icon": marker = new Icon(opts); break;
|
||||
}
|
||||
if (marker != null) {
|
||||
marker.addTo(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { World };
|
Reference in New Issue
Block a user