Migrate ClockControl to vue
This commit is contained in:
parent
4584410ae2
commit
c51d2ef554
@ -17,7 +17,7 @@
|
||||
<template>
|
||||
<div id="ui">
|
||||
<div id="ui__top-center" class="ui__section">
|
||||
<ClockControl v-if="clockControlEnabled" :leaflet="leaflet"></ClockControl>
|
||||
<ClockControl v-if="clockControlEnabled"></ClockControl>
|
||||
</div>
|
||||
|
||||
<div id="ui__top-left" class="ui__section section--vertical">
|
||||
|
@ -14,43 +14,205 @@
|
||||
- limitations under the License.
|
||||
-->
|
||||
|
||||
|
||||
<template>
|
||||
<div :class="{'clock': true, 'ui__element': true, 'ui__panel': digital}">
|
||||
<div class="clock__sun" :style="sunStyle">
|
||||
<SvgIcon :name="sunIcon"></SvgIcon>
|
||||
</div>
|
||||
<div class="clock__moon" :style="moonStyle">
|
||||
<SvgIcon :name="moonIcon"></SvgIcon>
|
||||
</div>
|
||||
<div v-if="showTime" :class="{'clock__time': true, 'day': minecraftTime?.day, 'night': minecraftTime?.night}">
|
||||
{{ formattedTime }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {computed, defineComponent, onMounted, onUnmounted} from "@vue/runtime-core";
|
||||
import {computed, defineComponent} from "@vue/runtime-core";
|
||||
import {useStore} from "@/store";
|
||||
import {ClockControl, ClockControlOptions} from "@/leaflet/control/ClockControl";
|
||||
import LiveAtlasLeafletMap from "@/leaflet/LiveAtlasLeafletMap";
|
||||
import {watch} from "vue";
|
||||
import SvgIcon from "@/components/SvgIcon.vue";
|
||||
import {getMinecraftTime} from "@/util";
|
||||
|
||||
import "@/assets/icons/clock_moon.svg";
|
||||
import "@/assets/icons/clock_moon_rain.svg";
|
||||
import "@/assets/icons/clock_moon_storm.svg";
|
||||
import "@/assets/icons/clock_sun.svg";
|
||||
import "@/assets/icons/clock_sun_rain.svg";
|
||||
import "@/assets/icons/clock_sun_storm.svg";
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
leaflet: {
|
||||
type: Object as () => LiveAtlasLeafletMap,
|
||||
required: true,
|
||||
}
|
||||
},
|
||||
|
||||
setup(props) {
|
||||
components: {SvgIcon},
|
||||
setup() {
|
||||
const store = useStore(),
|
||||
componentSettings = computed(() => store.state.components.clockControl);
|
||||
let control = new ClockControl(componentSettings.value as ClockControlOptions) as ClockControl;
|
||||
componentSettings = computed(() => store.state.components.clockControl),
|
||||
digital = computed(() => componentSettings.value!.showTimeOfDay && !componentSettings.value!.showWeather && componentSettings.value!.showDigitalClock),
|
||||
showTime = computed(() => componentSettings.value!.showDigitalClock),
|
||||
|
||||
watch(componentSettings, (newSettings) => {
|
||||
props.leaflet.removeControl(control);
|
||||
worldState = computed(() => store.state.currentWorldState),
|
||||
minecraftTime = computed(() => getMinecraftTime(worldState.value.timeOfDay)),
|
||||
|
||||
if(!newSettings) {
|
||||
return;
|
||||
}
|
||||
formattedTime = computed(() => {
|
||||
if (minecraftTime.value) {
|
||||
return [
|
||||
minecraftTime.value.hours.toString().padStart(2, '0'),
|
||||
minecraftTime.value.minutes.toString().padStart(2, '0')
|
||||
].join(':');
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}),
|
||||
|
||||
control = new ClockControl(newSettings as ClockControlOptions);
|
||||
props.leaflet.addControl(control);
|
||||
}, {deep: true});
|
||||
sunAngle = computed(() => {
|
||||
const timeOfDay = worldState.value.timeOfDay;
|
||||
|
||||
onMounted(() => props.leaflet.addControl(control));
|
||||
onUnmounted(() => props.leaflet.removeControl(control));
|
||||
},
|
||||
if (timeOfDay > 23100 || timeOfDay < 12900) {
|
||||
//day mode
|
||||
let movedTime = timeOfDay + 900;
|
||||
movedTime = (movedTime >= 24000) ? movedTime - 24000 : movedTime;
|
||||
//Now we have 0 -> 13800 for the day period
|
||||
//Divide by 13800*2=27600 instead of 24000 to compress day
|
||||
return ((movedTime) / 27600 * 2 * Math.PI);
|
||||
} else {
|
||||
//night mode
|
||||
const movedTime = timeOfDay - 12900;
|
||||
//Now we have 0 -> 10200 for the night period
|
||||
//Divide by 10200*2=20400 instead of 24000 to expand night
|
||||
return Math.PI + ((movedTime) / 20400 * 2 * Math.PI);
|
||||
}
|
||||
}),
|
||||
moonAngle = computed(() => sunAngle.value + Math.PI),
|
||||
|
||||
render() {
|
||||
return null;
|
||||
sunStyle = computed(() => {
|
||||
if (worldState.value.timeOfDay >= 0) {
|
||||
return {'transform': 'translate(' + Math.round(-50 * Math.cos(sunAngle.value)) + 'px, ' + Math.round(-50 * Math.sin(sunAngle.value)) + 'px)'};
|
||||
} else {
|
||||
return {'transform': 'translate(-150px, -150px)'};
|
||||
}
|
||||
}),
|
||||
|
||||
moonStyle = computed(() => {
|
||||
if (worldState.value.timeOfDay >= 0) {
|
||||
return {'transform': 'translate(' + Math.round(-50 * Math.cos(moonAngle.value)) + 'px, ' + Math.round(-50 * Math.sin(moonAngle.value)) + 'px)'};
|
||||
} else {
|
||||
return {'transform': 'translate(-150px, -150px)'};
|
||||
}
|
||||
}),
|
||||
|
||||
sunIcon = computed(() => {
|
||||
if (componentSettings.value!.showWeather) {
|
||||
if (worldState.value.thundering) {
|
||||
return 'clock_sun_storm';
|
||||
} else if (worldState.value.raining) {
|
||||
return 'clock_sun_rain';
|
||||
}
|
||||
}
|
||||
|
||||
return 'clock_sun';
|
||||
}),
|
||||
|
||||
moonIcon = computed(() => {
|
||||
if (componentSettings.value!.showWeather) {
|
||||
if (worldState.value.thundering) {
|
||||
return 'clock_moon_storm';
|
||||
} else if (worldState.value.raining) {
|
||||
return 'clock_moon_rain';
|
||||
}
|
||||
}
|
||||
|
||||
return 'clock_moon';
|
||||
});
|
||||
|
||||
return {
|
||||
digital,
|
||||
showTime,
|
||||
|
||||
minecraftTime,
|
||||
formattedTime,
|
||||
|
||||
sunStyle,
|
||||
moonStyle,
|
||||
|
||||
sunIcon,
|
||||
moonIcon
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../../scss/placeholders';
|
||||
|
||||
.clock {
|
||||
@extend %panel;
|
||||
position: relative;
|
||||
width: 15rem;
|
||||
height: 6rem;
|
||||
z-index: 50;
|
||||
font-family: monospace;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0.5rem 2rem;
|
||||
overflow: hidden;
|
||||
|
||||
.clock__time {
|
||||
text-align: center;
|
||||
font-size: 2rem;
|
||||
line-height: 2rem;
|
||||
margin-top: auto;
|
||||
background-color: var(--background-base);
|
||||
z-index: 1;
|
||||
padding: 0.1rem 0.1rem 0;
|
||||
border-radius: 0.3rem;
|
||||
|
||||
&.night {
|
||||
color: var(--text-night);
|
||||
}
|
||||
|
||||
&.day {
|
||||
color: var(--text-day);
|
||||
}
|
||||
|
||||
&.night, &.day {
|
||||
transition: color 8s 8s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.clock__sun,
|
||||
.clock__moon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
svg {
|
||||
width: 15rem;
|
||||
height: 12rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.clock--digital {
|
||||
justify-content: center;
|
||||
height: var(--ui-button-size);
|
||||
width: auto;
|
||||
|
||||
.clock__sun,
|
||||
.clock__moon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.clock__time {
|
||||
margin: 0;
|
||||
font-size: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px), (max-height: 480px) {
|
||||
transform: scale(calc((1/6)*5));
|
||||
transform-origin: top center
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
8
src/index.d.ts
vendored
8
src/index.d.ts
vendored
@ -18,6 +18,7 @@ import {State} from "@/store";
|
||||
import {DynmapUrlConfig} from "@/dynmap";
|
||||
import LiveAtlasMapDefinition from "@/model/LiveAtlasMapDefinition";
|
||||
import {
|
||||
ControlOptions,
|
||||
Coords,
|
||||
DoneCallback, FitBoundsOptions,
|
||||
InternalTiles, LatLng,
|
||||
@ -26,7 +27,6 @@ import {
|
||||
PolylineOptions
|
||||
} from "leaflet";
|
||||
import {CoordinatesControlOptions} from "@/leaflet/control/CoordinatesControl";
|
||||
import {ClockControlOptions} from "@/leaflet/control/ClockControl";
|
||||
import {LogoControlOptions} from "@/leaflet/control/LogoControl";
|
||||
import {globalMessages, serverMessages} from "../messages";
|
||||
import {LiveAtlasMarkerType} from "@/util/markers";
|
||||
@ -291,6 +291,12 @@ interface LiveAtlasComponentConfig {
|
||||
login: boolean;
|
||||
}
|
||||
|
||||
export interface ClockControlOptions extends ControlOptions {
|
||||
showTimeOfDay: boolean;
|
||||
showDigitalClock: boolean;
|
||||
showWeather: boolean;
|
||||
}
|
||||
|
||||
interface LiveAtlasPartialComponentConfig {
|
||||
markers?: {
|
||||
showLabels: boolean;
|
||||
|
@ -1,175 +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, DomUtil, Util, Control} from 'leaflet';
|
||||
import {getMinecraftTime} from '@/util';
|
||||
|
||||
import {watch} from "@vue/runtime-core";
|
||||
import {useStore} from "@/store";
|
||||
|
||||
import "@/assets/icons/clock_moon.svg";
|
||||
import "@/assets/icons/clock_moon_rain.svg";
|
||||
import "@/assets/icons/clock_moon_storm.svg";
|
||||
import "@/assets/icons/clock_sun.svg";
|
||||
import "@/assets/icons/clock_sun_rain.svg";
|
||||
import "@/assets/icons/clock_sun_storm.svg";
|
||||
import {LiveAtlasWorldState} from "@/index";
|
||||
|
||||
export interface ClockControlOptions extends ControlOptions {
|
||||
showTimeOfDay: boolean;
|
||||
showDigitalClock: boolean;
|
||||
showWeather: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaflet map control providing a clock which can display the current in-game time of day and weather
|
||||
*/
|
||||
export class ClockControl extends Control {
|
||||
declare options: ClockControlOptions;
|
||||
declare _container?: HTMLElement;
|
||||
|
||||
private _sun?: HTMLElement;
|
||||
private _moon?: HTMLElement;
|
||||
private _clock?: HTMLElement;
|
||||
private _currentMoonIcon?: string;
|
||||
private _currentSunIcon?: string;
|
||||
private _unwatchHandler?: Function;
|
||||
|
||||
constructor(options: ClockControlOptions) {
|
||||
super(Object.assign(options, {position: 'topcenter'}));
|
||||
|
||||
Util.setOptions(this, options);
|
||||
}
|
||||
|
||||
onAdd() {
|
||||
const digital = !this.options.showTimeOfDay && !this.options.showWeather && this.options.showDigitalClock,
|
||||
worldState = useStore().state.currentWorldState;
|
||||
|
||||
this._container = DomUtil.create('div', 'clock' + (digital ? ' clock--digital' : ''));
|
||||
this._sun = DomUtil.create('div', 'clock__sun', this._container);
|
||||
this._moon = DomUtil.create('div', 'clock__moon', this._container);
|
||||
|
||||
this._sun.style.transform = 'translate(-150px, -150px)';
|
||||
this._moon.style.transform = 'translate(-150px, -150px)';
|
||||
|
||||
this._sun!.innerHTML = `
|
||||
<svg class="svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon--clock_sun" />
|
||||
</svg>`;
|
||||
this._moon!.innerHTML = `
|
||||
<svg class="svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon--clock_moon" />
|
||||
</svg>`;
|
||||
|
||||
if (this.options.showDigitalClock) {
|
||||
this._clock = DomUtil.create('div', 'clock__time', this._container)
|
||||
}
|
||||
|
||||
this._unwatchHandler = watch(worldState, (newValue) => {
|
||||
this._update(newValue);
|
||||
}, { deep: true });
|
||||
|
||||
return this._container;
|
||||
}
|
||||
|
||||
onRemove() {
|
||||
if(this._unwatchHandler) {
|
||||
this._unwatchHandler();
|
||||
}
|
||||
}
|
||||
|
||||
_update(worldState: LiveAtlasWorldState) {
|
||||
const timeOfDay = worldState.timeOfDay;
|
||||
let sunAngle;
|
||||
|
||||
if (timeOfDay > 23100 || timeOfDay < 12900) {
|
||||
//day mode
|
||||
let movedTime = timeOfDay + 900;
|
||||
movedTime = (movedTime >= 24000) ? movedTime - 24000 : movedTime;
|
||||
//Now we have 0 -> 13800 for the day period
|
||||
//Divide by 13800*2=27600 instead of 24000 to compress day
|
||||
sunAngle = ((movedTime) / 27600 * 2 * Math.PI);
|
||||
} else {
|
||||
//night mode
|
||||
const movedTime = timeOfDay - 12900;
|
||||
//Now we have 0 -> 10200 for the night period
|
||||
//Divide by 10200*2=20400 instead of 24000 to expand night
|
||||
sunAngle = Math.PI + ((movedTime) / 20400 * 2 * Math.PI);
|
||||
}
|
||||
|
||||
const moonAngle = sunAngle + Math.PI;
|
||||
|
||||
if (timeOfDay >= 0) {
|
||||
this._sun!.style.transform = 'translate(' + Math.round(-50 * Math.cos(sunAngle)) + 'px, ' + Math.round(-50 * Math.sin(sunAngle)) + 'px)';
|
||||
this._moon!.style.transform = 'translate(' + Math.round(-50 * Math.cos(moonAngle)) + 'px, ' + Math.round(-50 * Math.sin(moonAngle)) + 'px)';
|
||||
} else {
|
||||
this._sun!.style.transform = 'translate(-150px, -150px)';
|
||||
this._moon!.style.transform = 'translate(-150px, -150px)';
|
||||
}
|
||||
|
||||
const minecraftTime = getMinecraftTime(timeOfDay);
|
||||
|
||||
if (this.options.showDigitalClock) {
|
||||
if (timeOfDay >= 0) {
|
||||
this._clock!.classList.remove(minecraftTime.night ? 'day' : 'night');
|
||||
this._clock!.classList.add(minecraftTime.day ? 'day' : 'night');
|
||||
this._clock!.textContent = [
|
||||
minecraftTime.hours.toString().padStart(2, '0'),
|
||||
minecraftTime.minutes.toString().padStart(2, '0')
|
||||
].join(':');
|
||||
} else {
|
||||
this._clock!.classList.remove(minecraftTime.night ? 'day' : 'night');
|
||||
this._clock!.textContent = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (this.options.showWeather) {
|
||||
if (worldState.thundering) {
|
||||
this._setSunIcon('clock_sun_storm');
|
||||
this._setMoonIcon('clock_moon_storm');
|
||||
} else if (worldState.raining) {
|
||||
this._setSunIcon('clock_sun_rain');
|
||||
this._setMoonIcon('clock_moon_rain');
|
||||
} else {
|
||||
this._setSunIcon('clock_sun');
|
||||
this._setMoonIcon('clock_moon');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_setSunIcon(icon: string) {
|
||||
if(this._sun && this._currentSunIcon !== icon) {
|
||||
this._sun!.innerHTML = `
|
||||
<svg class="svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon--${icon}" />
|
||||
</svg>`;
|
||||
this._currentSunIcon = icon;
|
||||
}
|
||||
}
|
||||
|
||||
_setMoonIcon(icon: string) {
|
||||
if(this._moon && this._currentMoonIcon !== icon) {
|
||||
this._moon!.innerHTML = `
|
||||
<svg class="svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icon--${icon}" />
|
||||
</svg>`;
|
||||
this._currentMoonIcon = icon;
|
||||
}
|
||||
}
|
||||
}
|
@ -282,78 +282,6 @@ img {
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.clock {
|
||||
@extend %panel;
|
||||
position: relative;
|
||||
width: 15rem;
|
||||
height: 6rem;
|
||||
z-index: 50;
|
||||
font-family: monospace;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 0.5rem 2rem;
|
||||
overflow: hidden;
|
||||
|
||||
.clock__time {
|
||||
text-align: center;
|
||||
font-size: 2rem;
|
||||
line-height: 2rem;
|
||||
margin-top: auto;
|
||||
background-color: var(--background-base);
|
||||
z-index: 1;
|
||||
padding: 0.1rem 0.1rem 0;
|
||||
border-radius: 0.3rem;
|
||||
|
||||
&.night {
|
||||
color: var(--text-night);
|
||||
}
|
||||
|
||||
&.day {
|
||||
color: var(--text-day);
|
||||
}
|
||||
|
||||
&.night, &.day {
|
||||
transition: color 8s 8s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.clock__sun,
|
||||
.clock__moon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
|
||||
svg {
|
||||
width: 15rem;
|
||||
height: 12rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.clock--digital {
|
||||
justify-content: center;
|
||||
height: var(--ui-button-size);
|
||||
width: auto;
|
||||
|
||||
.clock__sun,
|
||||
.clock__moon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.clock__time {
|
||||
margin: 0;
|
||||
font-size: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px), (max-height: 480px) {
|
||||
transform: scale(calc((1/6)*5));
|
||||
transform-origin: top center
|
||||
}
|
||||
}
|
||||
|
||||
.form {
|
||||
.form__group {
|
||||
margin-bottom: 1.5rem;
|
||||
|
12
src/util.ts
12
src/util.ts
@ -34,12 +34,22 @@ export const titleColoursRegex = /§[0-9a-f]/ig;
|
||||
export const netherWorldNameRegex = /[_\s]?nether([\s_]|$)/i;
|
||||
export const endWorldNameRegex = /(^|[_\s])end([\s_]|$)/i;
|
||||
|
||||
export interface MinecraftTime {
|
||||
serverTime: number;
|
||||
days: number;
|
||||
hours: number;
|
||||
minutes: number;
|
||||
seconds: number;
|
||||
day: boolean;
|
||||
night: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates 24 hour time of day and the current day from the given server time
|
||||
* @param {number} serverTime Server time in ticks
|
||||
* @returns The equivalent 24 hour time, current day and whether it is currently day or night
|
||||
*/
|
||||
export const getMinecraftTime = (serverTime: number) => {
|
||||
export const getMinecraftTime = (serverTime: number): MinecraftTime => {
|
||||
const day = serverTime >= 0 && serverTime < 13700;
|
||||
|
||||
return {
|
||||
|
Loading…
Reference in New Issue
Block a user