LiveAtlas/src/util/markers.ts

195 lines
6.5 KiB
TypeScript
Raw Normal View History

2020-12-16 16:54:41 +00:00
/*
* Copyright 2022 James Lyne
2020-12-16 16:54:41 +00:00
*
* Some portions of this file were taken from https://github.com/webbukkit/dynmap.
* These portions are Copyright 2020 Dynmap Contributors.
*
2021-07-25 14:12:40 +00:00
* 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
2020-12-16 16:54:41 +00:00
*
2021-07-25 14:12:40 +00:00
* http://www.apache.org/licenses/LICENSE-2.0
2020-12-16 16:54:41 +00:00
*
2021-07-25 14:12:40 +00:00
* 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.
2020-12-16 16:54:41 +00:00
*/
import {useStore} from "@/store";
import {ActionTypes} from "@/store/action-types";
import {DynmapMarkerUpdate} from "@/dynmap";
import {computed, watch} from "@vue/runtime-core";
import {ComputedRef} from "@vue/reactivity";
import {
LiveAtlasAreaMarker,
LiveAtlasCircleMarker,
LiveAtlasLineMarker,
LiveAtlasMarker,
LiveAtlasPointMarker
} from "@/index";
import {Layer} from "leaflet";
2022-01-15 18:45:01 +00:00
import {createCircleLayer, updateCircleLayer} from "@/util/circles";
import {createPointLayer, updatePointLayer} from "@/util/points";
import {createAreaLayer, updateAreaLayer} from "@/util/areas";
import {createLineLayer, updateLineLayer} from "@/util/lines";
import {GenericMarker} from "@/leaflet/marker/GenericMarker";
import LiveAtlasPolygon from "@/leaflet/vector/LiveAtlasPolygon";
import LiveAtlasPolyline from "@/leaflet/vector/LiveAtlasPolyline";
export type LiveAtlasMarkerUpdateCallback = ((update: DynmapMarkerUpdate) => void);
2021-01-26 14:32:48 +00:00
export enum LiveAtlasMarkerType {
POINT,
AREA,
LINE,
CIRCLE
}
let updateFrame = 0;
let pendingUpdates: ComputedRef;
const updateHandlers: Set<LiveAtlasMarkerUpdateCallback> = new Set();
const setUpdateHandlers: { [key:string]: Set<LiveAtlasMarkerUpdateCallback>} = {};
2022-02-26 14:57:16 +00:00
/**
* Starts handling of pending marker updates
*/
export const startUpdateHandling = () => {
const store = useStore();
pendingUpdates = computed(() => store.state.pendingMarkerUpdates.length);
watch(pendingUpdates, (newValue, oldValue) => {
if(newValue && newValue > 0 && oldValue === 0 && !updateFrame) {
updateFrame = requestAnimationFrame(() => handlePendingUpdates());
}
2021-05-25 22:31:03 +00:00
});
}
2021-05-25 22:31:03 +00:00
2022-02-26 14:57:16 +00:00
/**
* Stops handling of pending marker updates
*/
export const stopUpdateHandling = () => {
if(updateFrame) {
cancelAnimationFrame(updateFrame);
updateFrame = 0;
2021-01-26 14:32:48 +00:00
}
}
2021-01-26 14:32:48 +00:00
2022-02-26 14:57:16 +00:00
/**
* Registers the given callback as a global handler for marker updates
* @param {LiveAtlasMarkerUpdateCallback} callback The callback
*/
export const registerUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback) => {
updateHandlers.add(callback);
}
2022-02-26 14:57:16 +00:00
/**
* Unregisters the given callback as a global handler for marker updates
* @param {LiveAtlasMarkerUpdateCallback} callback The callback
*/
export const unregisterUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback) => {
updateHandlers.delete(callback);
}
2022-02-26 14:57:16 +00:00
/**
* Registers the given callback as a handler for marker updates in the given marker set
* @param {LiveAtlasMarkerUpdateCallback} callback The callback
* @param {string} set: The marker set id
*/
export const registerSetUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback, set: string) => {
if(!setUpdateHandlers[set]) {
setUpdateHandlers[set] = new Set();
}
setUpdateHandlers[set].add(callback);
}
2020-12-18 18:01:37 +00:00
2022-02-26 14:57:16 +00:00
/**
* Unregisters the given callback as a handler for marker updates in the given marker set
* @param {LiveAtlasMarkerUpdateCallback} callback The callback
* @param {string} set: The marker set id
*/
export const unregisterSetUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback, set: string) => {
if(!setUpdateHandlers[set]) {
return;
2021-01-26 14:32:48 +00:00
}
setUpdateHandlers[set].delete(callback);
}
2021-01-26 14:32:48 +00:00
2022-02-26 14:57:16 +00:00
/**
* Handles pending marker updates, if any exist
* Up to 10 updates will be taken from the list and the appropriate registered update handlers will be called
* If further updates remain, an animation frame will be scheduled for further calls
* @private
*/
const handlePendingUpdates = async () => {
const store = useStore(),
updates = await store.dispatch(ActionTypes.POP_MARKER_UPDATES, 10);
2021-01-26 14:32:48 +00:00
for(const update of updates) {
updateHandlers.forEach(callback => callback(update));
if(setUpdateHandlers[update.set]) {
setUpdateHandlers[update.set].forEach(callback => callback(update));
}
2021-01-26 14:32:48 +00:00
}
if(pendingUpdates.value) {
// eslint-disable-next-line no-unused-vars
updateFrame = requestAnimationFrame(() => handlePendingUpdates());
} else {
updateFrame = 0;
}
};
2022-02-26 14:57:16 +00:00
/**
* Creates the appropriate type of marker layer for the given {@link LiveAtlasMarker}
* @param {LiveAtlasMarker} options Marker options
* @param {Function} converter Function for projecting the marker location onto the map
* @returns The created layer
* @see createPointLayer
* @see createAreaLayer
* @see createCircleLayer
* @see createLineLayer
*/
2022-01-15 18:45:01 +00:00
export const createMarkerLayer = (options: LiveAtlasMarker, converter: Function): Layer => {
switch(options.type) {
case LiveAtlasMarkerType.POINT:
2022-01-15 18:45:01 +00:00
return createPointLayer(options as LiveAtlasPointMarker, converter);
case LiveAtlasMarkerType.AREA:
2022-01-15 18:45:01 +00:00
return createAreaLayer(options as LiveAtlasAreaMarker, converter);
case LiveAtlasMarkerType.LINE:
2022-01-15 18:45:01 +00:00
return createLineLayer(options as LiveAtlasLineMarker, converter);
case LiveAtlasMarkerType.CIRCLE:
2022-01-15 18:45:01 +00:00
return createCircleLayer(options as LiveAtlasCircleMarker, converter);
}
}
2022-02-26 14:57:16 +00:00
/**
* Updates or creates an appropriate type of marker layer with the given options
* @param {?Layer} marker Optional existing marker layer to update
* @param {?LiveAtlasMarker} options Marker options
* @param {Function} converter Function for projecting the marker location onto the map
* @returns The created layer
* @see updatePointLayer
* @see updateAreaLayer
* @see updateCircleLayer
* @see updateLineLayer
*/
2022-01-15 18:45:01 +00:00
export const updateMarkerLayer = (marker: Layer | undefined, options: LiveAtlasMarker, converter: Function): Layer => {
switch(options.type) {
case LiveAtlasMarkerType.POINT:
2022-01-15 18:45:01 +00:00
return updatePointLayer(marker as GenericMarker, options as LiveAtlasPointMarker, converter);
case LiveAtlasMarkerType.AREA:
2022-01-15 18:45:01 +00:00
return updateAreaLayer(marker as LiveAtlasPolygon | LiveAtlasPolyline, options as LiveAtlasAreaMarker, converter);
case LiveAtlasMarkerType.LINE:
2022-01-15 18:45:01 +00:00
return updateLineLayer(marker as LiveAtlasPolyline, options as LiveAtlasLineMarker, converter);
case LiveAtlasMarkerType.CIRCLE:
2022-01-15 18:45:01 +00:00
return updateCircleLayer(marker as LiveAtlasPolyline | LiveAtlasPolygon, options as LiveAtlasCircleMarker, converter);
}
}