Migrate CoordinatesControl to vue

This commit is contained in:
James Lyne 2022-06-25 13:14:57 +01:00
parent c51d2ef554
commit 7471bb794f
4 changed files with 137 additions and 228 deletions

View File

@ -14,12 +14,23 @@
- limitations under the License. - limitations under the License.
--> -->
<template>
<div class="ui__element ui__panel location">
<span class="value coordinates" :data-label="componentSettings.label">{{ formattedCoordinates }}</span>
<span v-if="componentSettings.showChunk" class="value chunk"
:data-label="chunkLabel">{{ formattedChunk }}</span>
<span v-if="componentSettings.showRegion" class="value region"
:data-label="regionLabel">{{ formattedRegion }}</span>
</div>
</template>
<script lang="ts"> <script lang="ts">
import {computed, defineComponent, onMounted, onUnmounted} from "@vue/runtime-core"; import {computed, defineComponent, onUnmounted, watch} from "@vue/runtime-core";
import {useStore} from "@/store"; import {useStore} from "@/store";
import {CoordinatesControl, CoordinatesControlOptions} from "@/leaflet/control/CoordinatesControl";
import LiveAtlasLeafletMap from "@/leaflet/LiveAtlasLeafletMap"; import LiveAtlasLeafletMap from "@/leaflet/LiveAtlasLeafletMap";
import {watch} from "vue"; import {onMounted, ref} from "vue";
import {Coordinate, CoordinatesControlOptions} from "@/index";
import {LeafletMouseEvent} from "leaflet";
export default defineComponent({ export default defineComponent({
props: { props: {
@ -31,26 +42,129 @@ export default defineComponent({
setup(props) { setup(props) {
const store = useStore(), const store = useStore(),
componentSettings = computed(() => store.state.components.coordinatesControl); componentSettings = computed(() => store.state.components.coordinatesControl),
let control = new CoordinatesControl(componentSettings.value as CoordinatesControlOptions); currentMap = computed(() => store.state.currentMap),
watch(componentSettings, (newSettings) => { chunkLabel = computed(() => store.state.messages.locationChunk),
props.leaflet.removeControl(control); regionLabel = computed(() => store.state.messages.locationRegion),
if(!newSettings) { coordinates = ref<Coordinate|null>(null),
formattedCoordinates = computed(() => {
if(coordinates.value) {
const x = Math.round(coordinates.value.x).toString().padStart(5, ' '),
y = coordinates.value.y.toString().padStart(3, ' '),
z = Math.round(coordinates.value.z).toString().padStart(5, ' ');
return componentSettings.value!.showY ? `${x}, ${y}, ${z}` : `${x}, ${z}`;
} else {
return componentSettings.value!.showY ? '-----, ---, -----' : '-----, -----';
}
}),
formattedChunk = computed(() => {
if(coordinates.value) {
const chunkX = Math.floor(coordinates.value.x / 16).toString().padStart(4, ' '),
chunkZ = Math.floor(coordinates.value.z / 16).toString().padStart(4, ' ');
return `${chunkX}, ${chunkZ}`;
} else {
return '----, ----'
}
}),
formattedRegion = computed(() => {
if(coordinates.value) {
const regionX = Math.floor(coordinates.value.x / 512).toString().padStart(3, ' '),
regionZ = Math.floor(coordinates.value.z / 512).toString().padStart(3, ' ');
return `r.${regionX}, ${regionZ}.mca`;
} else {
return '--------------';
}
});
const onMouseMove = (event: LeafletMouseEvent) => {
if (!store.state.currentMap) {
return; return;
} }
control = new CoordinatesControl(newSettings as CoordinatesControlOptions); coordinates.value = store.state.currentMap.latLngToLocation(event.latlng, store.state.currentWorld!.seaLevel + 1);
props.leaflet.addControl(control); }
}, {deep: true});
onMounted(() => props.leaflet.addControl(control)); const onMouseOut = () => coordinates.value = null;
onUnmounted(() => props.leaflet.removeControl(control));
},
render() { watch(currentMap, newValue => {
return null; if(!newValue) {
coordinates.value = null;
}
});
onMounted(() => {
props.leaflet.on('mousemove', onMouseMove);
props.leaflet.on('mouseout', onMouseOut);
});
onUnmounted(() => {
props.leaflet.off('mousemove', onMouseMove);
props.leaflet.off('mouseout', onMouseOut);
});
return {
componentSettings,
chunkLabel,
regionLabel,
formattedCoordinates,
formattedChunk,
formattedRegion
}
} }
}) })
</script> </script>
<style lang="scss" scoped>
.location {
display: flex;
align-items: center;
padding: 0.6rem 1.5rem;
flex-direction: row;
.value {
line-height: 1;
font-family: monospace;
white-space: pre;
font-size: 2rem;
&[data-label]:before {
content: attr(data-label);
display: block;
line-height: 1;
margin-bottom: 0.5rem;
font-size: 1.25rem;
font-family: Raleway, sans-serif;;
}
& + .value {
margin-left: 2rem;
}
}
@media (max-width: 600px) {
.region {
display: none;
}
}
@media (max-width: 480px), (max-height: 480px) {
.value {
font-size: 1.6rem;
}
}
@media (max-width: 384px) {
.chunk {
display: none;
}
}
}
</style>

8
src/index.d.ts vendored
View File

@ -26,7 +26,6 @@ import {
PointTuple, PointTuple,
PolylineOptions PolylineOptions
} from "leaflet"; } from "leaflet";
import {CoordinatesControlOptions} from "@/leaflet/control/CoordinatesControl";
import {LogoControlOptions} from "@/leaflet/control/LogoControl"; import {LogoControlOptions} from "@/leaflet/control/LogoControl";
import {globalMessages, serverMessages} from "../messages"; import {globalMessages, serverMessages} from "../messages";
import {LiveAtlasMarkerType} from "@/util/markers"; import {LiveAtlasMarkerType} from "@/util/markers";
@ -297,6 +296,13 @@ export interface ClockControlOptions extends ControlOptions {
showWeather: boolean; showWeather: boolean;
} }
export interface CoordinatesControlOptions extends ControlOptions {
showY: boolean;
showRegion: boolean;
showChunk: boolean;
label: string;
}
interface LiveAtlasPartialComponentConfig { interface LiveAtlasPartialComponentConfig {
markers?: { markers?: {
showLabels: boolean; showLabels: boolean;

View File

@ -1,167 +0,0 @@
/*
* Copyright 2022 James Lyne
*
* Some portions of this file were taken from https://github.com/webbukkit/dynmap.
* These portions are Copyright 2020 Dynmap Contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {ControlOptions, LeafletMouseEvent, Control, Map, DomUtil, Util} from 'leaflet';
import {useStore} from "@/store";
import {Coordinate} from "@/index";
const store = useStore();
export interface CoordinatesControlOptions extends ControlOptions {
showY: boolean;
showRegion: boolean;
showChunk: boolean;
label: string;
}
/**
* Leaflet map control which displays in-game block coordinates when hovering over or tapping the map
*/
export class CoordinatesControl extends Control {
declare options: CoordinatesControlOptions;
declare _map ?: Map;
private _location?: Coordinate;
private _locationChanged: boolean = false;
private readonly _coordsContainer: HTMLSpanElement;
private readonly _regionContainer: HTMLSpanElement;
private readonly _chunkContainer: HTMLSpanElement;
constructor(options: CoordinatesControlOptions) {
super(options);
this._coordsContainer = DomUtil.create('span', 'value coordinates');
this._chunkContainer = DomUtil.create('span', 'value chunk');
this._regionContainer = DomUtil.create('span', 'value region');
options.position = 'bottomleft';
Util.setOptions(this, options);
}
onAdd(map: Map) {
const container = DomUtil.create('div', 'leaflet-control-coordinates');
this._coordsContainer.textContent = this.options.showY ? '-----, ---, -----' : '-----, -----';
this._coordsContainer.dataset.label = this.options.label;
container.appendChild(this._coordsContainer);
if (this.options.showRegion) {
this._regionContainer.textContent = '--------------';
this._regionContainer.dataset.label = store.state.messages.locationRegion;
container.appendChild(this._regionContainer);
}
if (this.options.showChunk) {
this._chunkContainer.textContent = '----, ----';
this._chunkContainer.dataset.label = store.state.messages.locationChunk;
container.appendChild(this._chunkContainer);
}
map.on('mousemove', this._onMouseMove, this);
map.on('mouseout', this._onMouseOut, this);
return container;
}
remove() {
if (!this._map) {
return this;
}
this._map.off('mousemove', this._onMouseMove, this);
this._map.off('mouseout', this._onMouseOut, this);
super.remove();
return this;
}
_onMouseMove(event: LeafletMouseEvent) {
if (!this._map || !store.state.currentMap) {
return;
}
this._location = store.state.currentMap.latLngToLocation(event.latlng, store.state.currentWorld!.seaLevel + 1);
if(!this._locationChanged) {
this._locationChanged = true;
requestAnimationFrame(() => this._update());
}
}
_onMouseOut() {
if (!this._map) {
return;
}
this._location = undefined;
if(!this._locationChanged) {
this._locationChanged = true;
requestAnimationFrame(() => this._update());
}
}
_update() {
if (!this._map || !store.state.currentWorld || !this._locationChanged) {
return;
}
this._locationChanged = false;
if(!this._location) {
if (this.options.showY) {
this._coordsContainer.textContent = '-----, ---, -----';
} else {
this._coordsContainer.textContent = '-----, -----';
}
if (this.options.showRegion) {
this._regionContainer.textContent = '--------------';
}
if (this.options.showChunk) {
this._chunkContainer.textContent = '----, ----';
}
return;
}
const x = Math.round(this._location.x).toString().padStart(5, ' '),
y = this._location.y.toString().padStart(3, ' '),
z = Math.round(this._location.z).toString().padStart(5, ' '),
regionX = Math.floor(this._location.x / 512).toString().padStart(3, ' '),
regionZ = Math.floor(this._location.z / 512).toString().padStart(3, ' '),
chunkX = Math.floor(this._location.x / 16).toString().padStart(4, ' '),
chunkZ = Math.floor(this._location.z / 16).toString().padStart(4, ' ');
if (this.options.showY) {
this._coordsContainer.textContent = `${x}, ${y}, ${z}`;
} else {
this._coordsContainer.textContent = `${x}, ${z}`;
}
if (this.options.showRegion) {
this._regionContainer.textContent = `r.${regionX}, ${regionZ}.mca`;
}
if (this.options.showChunk) {
this._chunkContainer.textContent = `${chunkX}, ${chunkZ}`;
}
}
}

View File

@ -99,50 +99,6 @@
} }
} }
.leaflet-control-coordinates {
display: flex;
align-items: center;
padding: 0.5rem 1.5rem;
.value {
line-height: 1;
font-family: monospace;
white-space: pre;
font-size: 2rem;
&[data-label]:before {
content: attr(data-label);
display: block;
line-height: 1;
margin-bottom: 0.5rem;
font-size: 1.25rem;
font-family: Raleway, sans-serif;;
}
& + .value {
margin-left: 2rem;
}
}
@media (max-width: 600px) {
.region {
display: none;
}
}
@media (max-width: 480px), (max-height: 480px) {
.value {
font-size: 1.6rem;
}
}
@media (max-width: 384px) {
.chunk {
display: none;
}
}
}
.leaflet-control-layers { .leaflet-control-layers {
width: auto; width: auto;
border: none; border: none;