Some jsdocs

This commit is contained in:
James Lyne 2022-02-26 14:57:16 +00:00
parent f4481a1d6c
commit 0a1842f77d
19 changed files with 405 additions and 25 deletions

View File

@ -21,6 +21,9 @@ import {watch} from "@vue/runtime-core";
import "@/assets/icons/chat.svg";
/**
* Leaflet map control providing a chat button which opens the chatbox on click
*/
export class ChatControl extends Control {
declare options: ControlOptions

View File

@ -37,6 +37,9 @@ export interface ClockControlOptions extends ControlOptions {
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;

View File

@ -30,6 +30,9 @@ export interface CoordinatesControlOptions extends ControlOptions {
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;

View File

@ -24,6 +24,9 @@ import { toClipboard } from '@soerenmartius/vue3-clipboard';
import {notify} from "@kyvg/vue3-notification";
import {computed} from "@vue/runtime-core";
/**
* Leaflet map control providing a button for copying a link for the current map view to the clipboard
*/
export class LinkControl extends Control {
declare options: ControlOptions

View File

@ -30,6 +30,10 @@ import LayersOptions = Control.LayersOptions;
const store = useStore();
/**
* Extension of leaflet's standard {@link Control.Layers}
* Sorts layers by position, adds additional keyboard navigation, adjusts to viewport size and tracks expanded state in vuex
*/
export class LiveAtlasLayerControl extends Control.Layers {
declare _map ?: LeafletMap;
declare _overlaysList?: HTMLElement;

View File

@ -37,6 +37,9 @@ export interface LoadingControlOptions extends ControlOptions {
delayIndicator?: number;
}
/**
* Leaflet map control which displays a loading spinner when any tiles are loading
*/
export class LoadingControl extends Control {
declare options: LoadingControlOptions;

View File

@ -26,6 +26,9 @@ import {ActionTypes} from "@/store/action-types";
import {notify} from "@kyvg/vue3-notification";
import LiveAtlasLeafletMap from "@/leaflet/LiveAtlasLeafletMap";
/**
* Leaflet map control providing a login/logout button which opens the login modal/logs out on click
*/
export class LoginControl extends Control {
declare _map: LiveAtlasLeafletMap;
declare options: ControlOptions;

View File

@ -25,6 +25,10 @@ export interface LogoControlOptions extends ControlOptions {
text: string;
}
/**
* Leaflet map control which displays an arbitrary image or text with an optional link
* Intended for use for dynmap logo components
*/
export class LogoControl extends Control {
declare options: LogoControlOptions;

View File

@ -22,7 +22,7 @@ import {
LiveAtlasDimension,
LiveAtlasGlobalMessageConfig,
LiveAtlasLocation,
LiveAtlasMessageConfig,
LiveAtlasMessageConfig, LiveAtlasParsedUrl,
} from "@/index";
import {notify} from "@kyvg/vue3-notification";
import {globalMessages, serverMessages} from "../messages";
@ -34,6 +34,11 @@ export const titleColoursRegex = /§[0-9a-f]/ig;
export const netherWorldNameRegex = /[_\s]?nether([\s_]|$)/i;
export const endWorldNameRegex = /(^|[_\s])end([\s_]|$)/i;
/**
* 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) => {
const day = serverTime >= 0 && serverTime < 13700;
@ -51,14 +56,26 @@ export const getMinecraftTime = (serverTime: number) => {
};
}
export const parseUrl = (url: URL) => {
/**
* Parses the given {@link URL} into a {@link LiveAtlasParsedUrl}, if the URL matches any known URL formats
* @param {URL} url The URL to parse
* @returns {LiveAtlasParsedUrl | null} A LiveAtlasParsedUrl if the provided URL matched any known URL formats,
* otherwise null
*/
export const parseUrl = (url: URL): LiveAtlasParsedUrl | null => {
const query = new URLSearchParams(url.search),
hash = url.hash.replace('#', '');
return hash ? parseMapHash(hash) : parseMapSearchParams(query);
}
export const parseMapHash = (hash: string) => {
/**
* Parses the given hash into a {@link LiveAtlasParsedUrl}, if the hash matches the LiveAtlas URL hash format
* @param {string} hash The hash to parse
* @returns {LiveAtlasParsedUrl | null} A LiveAtlasParsedUrl if the provided hash matched the LiveAtlas URL
* hash format, otherwise null
*/
export const parseMapHash = (hash: string): LiveAtlasParsedUrl | null => {
const parts = hash.replace('#', '').split(';');
const world = parts[0] || undefined,
@ -81,7 +98,13 @@ export const parseMapHash = (hash: string) => {
});
}
export const parseMapSearchParams = (query: URLSearchParams) => {
/**
* Parses the given {@link URLSearchParams} into a {@link LiveAtlasParsedUrl}, if it matches any known query string formats
* @param {URLSearchParams} query The URLSearchParams to parse
* @returns {LiveAtlasParsedUrl | null} A LiveAtlasParsedUrl if the provided hash matched the LiveAtlas URL
* hash format, otherwise null
*/
export const parseMapSearchParams = (query: URLSearchParams): LiveAtlasParsedUrl | null => {
const world = query.get('worldname') /* Dynmap */ || query.get('world') /* Pl3xmap */ || undefined,
map = query.has('worldname') ? query.get('mapname') || undefined : undefined, //Dynmap only
location = [
@ -104,6 +127,15 @@ export const parseMapSearchParams = (query: URLSearchParams) => {
});
}
/**
* Validates the given {@link LiveAtlasParsedUrl} to ensure all required properties are present and have valid values
* @param {LiveAtlasParsedUrl} parsed The parsed URL to validate
* @return {LiveAtlasParsedUrl | null} The parsed URL, possibly modified to ensure validity, or null if it is invalid
* and cannot be fixed
* @see {@link parseMapSearchParams}
* @see {@link parseMapHash}
* @private
*/
const validateParsedUrl = (parsed: any) => {
if(typeof parsed.zoom !== 'undefined' && (isNaN(parsed.zoom) || parsed.zoom < 0 || !isFinite(parsed.zoom))) {
parsed.zoom = undefined;
@ -116,6 +148,14 @@ const validateParsedUrl = (parsed: any) => {
return parsed;
}
/**
* Generates a LiveAtlas formatted URL hash representing the given {@link LiveAtlasMapDefinition}map, {@link Coordinate}
* location and zoom level
* @param {LiveAtlasMapDefinition} map The map
* @param {Coordinate} location The location
* @param {number} zoom The zoom level
* @return {string} The URL hash (including the #), or an empty string if a valid hash cannot be constructed
*/
export const getUrlForLocation = (map: LiveAtlasMapDefinition, location: Coordinate, zoom: number): string => {
const x = Math.round(location.x),
y = Math.round(location.y),
@ -129,6 +169,10 @@ export const getUrlForLocation = (map: LiveAtlasMapDefinition, location: Coordin
return `#${map.world.name};${map.name};${locationString};${zoom}`;
}
/**
* Focuses the first html element which matches the given selector, if any
* @param {string} selector The selector string
*/
export const focus = (selector: string) => {
const element = document.querySelector(selector);
@ -139,31 +183,74 @@ export const focus = (selector: string) => {
const decodeTextarea = document.createElement('textarea');
/**
* Decodes HTML entities in the given string using a <textarea>
* @param {string} text The text to decode HTML entities in
* @returns {string} The given text with any HTML entities decoded
*/
export const decodeHTMLEntities = (text: string) => {
decodeTextarea.innerHTML = text;
return decodeTextarea.textContent || '';
}
/**
* Strips HTML from the given string using a contextual {@link DocumentFragment} and converts <br>s to spaces
* @param {string} text The text to strip HTML from
* @returns {string} The given text with HTML stripped
*/
export const stripHTML = (text: string) => {
return documentRange.createContextualFragment(text.replace(brToSpaceRegex,'&nbsp;')).textContent || '';
}
/**
* Default success callback function for VueClipboard, will display a notification with the configured copy success
* message
*/
export const clipboardSuccess = () => () => notify(useStore().state.messages.copyToClipboardSuccess);
/**
* Default error callback function for VueClipboard, will display a notification with the configured copy error
* message
*/
export const clipboardError = () => (e: Error) => {
notify({ type: 'error', text: useStore().state.messages.copyToClipboardError });
console.error('Error copying to clipboard', e);
};
/**
* Creates a {@link LiveAtlasMessageConfig} from the provided config object. The provided object will be checked for all
* expected LiveAtlasMessageConfig messages, with fallback "Missing message" messages being used when a message is
* missing from the provided object.
* @param {Object} config Config object containing messages to include in the final LiveAtlasMessageConfig. Should
* contain a complete or subset of keys from LiveAtlasMessageConfig, additional keys will be ignored.
*/
export const getMessages = (config: any = {}) => {
return Object.assign(_getMessages(globalMessages, config),
_getMessages(serverMessages, config)) as LiveAtlasMessageConfig;
}
/**
* Creates a {@link LiveAtlasGlobalMessageConfig} from the provided config object. The provided object will be checked
* for all expected LiveAtlasGlobalMessageConfig messages, with fallback "Missing message" messages being used
* when a message is missing from the provided object.
* @param {Object} config Config object containing messages to include in the final LiveAtlasGlobalMessageConfig.
* Should contain a complete or subset of keys from LiveAtlasGlobalMessageConfig, additional keys will be ignored.
*/
export const getGlobalMessages = (config: any = {}) => {
return _getMessages(globalMessages, config) as LiveAtlasGlobalMessageConfig;
}
/**
* Creates an object containing the keys present in the messageKeys object and the values present in the config object.
*
* For each key, the config object is checked for a corresponding value. A fallback "Missing message" value is used if
* config object does not contain a value.
* @param {Object} messageKeys The object to take the keys from
* @param {Object} config The object to take the values from, if present
* @see {@link getMessages}
* @see {@link getGlobalMessages}
* @private
*/
const _getMessages = (messageKeys: any, config: any = {}) => {
const messages: any = {};
@ -190,7 +277,7 @@ export const getBounds = (x: number[], y: number[], z: number[]): LiveAtlasBound
}
/**
* Determines the bounds required to enclose the given array of {@see Coordinate}s
* Determines the bounds required to enclose the given array of {@link Coordinate}s
* Multiple dimension arrays are accepted and will be handled recursively
* @param {Coordinate[]} points Points to determine the bounds for
* @returns {LiveAtlasBounds} The calculated bounds
@ -220,7 +307,7 @@ export const getBoundsFromPoints = (points: Coordinate[]): LiveAtlasBounds => {
}
/**
* Determines the center point of the given {@see LiveAtlasBounds}
* Determines the center point of the given {@link LiveAtlasBounds}
* @param {LiveAtlasBounds} bounds The bounds to find the center point for
* @return {LiveAtlasLocation} The center point
*/
@ -233,7 +320,8 @@ export const getMiddle = (bounds: LiveAtlasBounds): LiveAtlasLocation => {
}
/**
* Creates an "allow-scripts" sandboxed <iframe> to be used by {@see runSandboxed}
* Creates an "allow-scripts" sandboxed <iframe>
* @see {@link runSandboxed}
* @returns {Window} The iframe's contentWindow
*/
const createIframeSandbox = () => {

View File

@ -23,6 +23,12 @@ import LiveAtlasPolygon from "@/leaflet/vector/LiveAtlasPolygon";
import {Coordinate, LiveAtlasAreaMarker} from "@/index";
import {arePointsEqual, createPopup, isStyleEqual, tooltipOptions} from "@/util/paths";
/**
* Creates a {@link LiveAtlasPolyline} or {@link LiveAtlasPolygon} with the given options
* @param {LiveAtlasAreaMarker} options Marker options
* @param {Function} converter Function for projecting the marker location onto the map
* @return The created LiveAtlasPolyline or LiveAtlasPolygon
*/
export const createAreaLayer = (options: LiveAtlasAreaMarker, converter: Function): LiveAtlasPolyline | LiveAtlasPolygon => {
const outline = !options.style.fillOpacity || (options.style.fillOpacity <= 0),
points = options.points.map(projectPointsMapCallback, converter) as LatLngExpression[] | LatLngExpression[][],
@ -39,6 +45,13 @@ export const createAreaLayer = (options: LiveAtlasAreaMarker, converter: Functio
return area;
};
/**
* Updates or creates a {@link LiveAtlasPolyline} or {@link LiveAtlasPolygon} with the given options
* @param {LiveAtlasPolyline | LiveAtlasPolygon} area Optional existing LiveAtlasPolyline or LiveAtlasPolygon
* @param {LiveAtlasAreaMarker} options Marker options
* @param {Function} converter Function for projecting the marker location onto the map
* @returns The created or updated LiveAtlasPolyline or LiveAtlasPolygon
*/
export const updateAreaLayer = (area: LiveAtlasPolyline | LiveAtlasPolygon | undefined, options: LiveAtlasAreaMarker, converter: Function): LiveAtlasPolyline | LiveAtlasPolygon => {
if (!area) {
return createAreaLayer(options, converter);
@ -80,6 +93,14 @@ export const updateAreaLayer = (area: LiveAtlasPolyline | LiveAtlasPolygon | und
return area;
};
/**
* Recursively applies the given function to the given array of {@link Coordinate}
* @param point
* @see {@link createAreaLayer}
* @see {@link updateAreaLayer}
* @returns Projected points as {@link LatLngExpression}
* @private
*/
const projectPointsMapCallback = function(this: Function, point: Coordinate | Coordinate[] | Coordinate[][]): LatLngExpression | LatLngExpression[] {
if(Array.isArray(point)) {
return point.map(projectPointsMapCallback, this) as LatLngExpression[];
@ -89,6 +110,14 @@ const projectPointsMapCallback = function(this: Function, point: Coordinate | Co
}
};
/**
* Calculates shape points for the given individual x y and z arrays
* @param {number[]} x Array of x coordinates
* @param {[number, number]} y Array of y coordinates
* @param {number[]} z Array of z coordinates
* @param outline Whether the resulting points will be used in a shape without a fill color
* @returns Array of Coordinates
*/
export const getPoints = (x: number[], y: [number, number], z: number[], outline: boolean): Coordinate[] | Coordinate[][] => {
if (x.length === 2) { /* Only 2 points */
if (y[0] === y[1]) {
@ -105,7 +134,16 @@ export const getPoints = (x: number[], y: [number, number], z: number[], outline
}
};
export const get3DBoxPoints = (x: number[], y: [number, number], z: number[]): Coordinate[][] => {
/**
* Calculates cuboid points for the given individual x y and z arrays
* @param {number[]} x Array of x coordinates
* @param {[number, number]} y Array of y coordinates
* @param {number[]} z Array of z coordinates
* @private
* @see {@link getPoints}
* @returns Array of Coordinates
*/
const get3DBoxPoints = (x: number[], y: [number, number], z: number[]): Coordinate[][] => {
const maxX = x[0],
minX = x[1],
maxY = y[0],
@ -148,7 +186,17 @@ export const get3DBoxPoints = (x: number[], y: [number, number], z: number[]): C
];
};
export const get2DBoxPoints = (x: number[], y: [number, number], z: number[], outline: boolean): Coordinate[] => {
/**
* Calculates rectangle points for the given individual x y and z arrays
* @param {number[]} x Array of x coordinates
* @param {[number, number]} y Array of y coordinates
* @param {number[]} z Array of z coordinates
* @param outline Whether the resulting points will be used in a shape without a fill color
* @private
* @see {@link getPoints}
* @returns Array of Coordinates
*/
const get2DBoxPoints = (x: number[], y: [number, number], z: number[], outline: boolean): Coordinate[] => {
const maxX = x[0],
minX = x[1],
minY = y[1],
@ -173,7 +221,16 @@ export const get2DBoxPoints = (x: number[], y: [number, number], z: number[], ou
}
};
export const get3DShapePoints = (x: number[], y: [number, number], z: number[]): Coordinate[][] => {
/**
* Calculates non-cuobidal 3d shape points for the given individual x y and z arrays
* @param {number[]} x Array of x coordinates
* @param {[number, number]} y Array of y coordinates
* @param {number[]} z Array of z coordinates
* @private
* @see {@link getPoints}
* @returns Array of Coordinates
*/
const get3DShapePoints = (x: number[], y: [number, number], z: number[]): Coordinate[][] => {
const toplist = [],
botlist = [],
polylist = [];
@ -198,7 +255,17 @@ export const get3DShapePoints = (x: number[], y: [number, number], z: number[]):
return polylist;
};
export const get2DShapePoints = (x: number[], y: [number, number], z: number[], outline: boolean): Coordinate[] => {
/**
* Calculates non-quadrilateral 2d shape points for the given individual x y and z arrays
* @param {number[]} x Array of x coordinates
* @param {[number, number]} y Array of y coordinates
* @param {number[]} z Array of z coordinates
* @param outline Whether the resulting points will be used in a shape without a fill color
* @private
* @see {@link getPoints}
* @returns Array of Coordinates
*/
const get2DShapePoints = (x: number[], y: [number, number], z: number[], outline: boolean): Coordinate[] => {
const points = [];
for (let i = 0; i < x.length; i++) {

View File

@ -23,6 +23,12 @@ import LiveAtlasPolygon from "@/leaflet/vector/LiveAtlasPolygon";
import {LiveAtlasCircleMarker} from "@/index";
import {createPopup, tooltipOptions} from "@/util/paths";
/**
* Creates a {@link LiveAtlasPolygon} with the given options
* @param {LiveAtlasCircleMarker} options Marker options
* @param {Function} converter Function for projecting the marker location onto the map
* @return The created LiveAtlasPolygon
*/
export const createCircleLayer = (options: LiveAtlasCircleMarker, converter: Function): LiveAtlasPolyline | LiveAtlasPolygon => {
const outline = !options.style.fillOpacity || (options.style.fillOpacity <= 0),
points = getCirclePoints(options, converter, outline),
@ -39,6 +45,13 @@ export const createCircleLayer = (options: LiveAtlasCircleMarker, converter: Fun
return circle;
};
/**
* Updates or creates a {@link LiveAtlasPolyline} with the given options
* @param {?LiveAtlasPolyline | LiveAtlasPolygon | undefined} circle Optional existing LiveAtlasPolyline or LiveAtlasPolygons
* @param {LiveAtlasCircleMarker} options Marker options
* @param {Function} converter Function for projecting the marker location onto the map
* @returns The created or updated LiveAtlasPolyline or LiveAtlasPolygon
*/
export const updateCircleLayer = (circle: LiveAtlasPolyline | LiveAtlasPolygon | undefined, options: LiveAtlasCircleMarker, converter: Function): LiveAtlasPolyline | LiveAtlasPolygon => {
if (!circle) {
return createCircleLayer(options, converter);
@ -66,6 +79,13 @@ export const updateCircleLayer = (circle: LiveAtlasPolyline | LiveAtlasPolygon |
return circle;
}
/**
* Calculates projected points for the given {@link LiveAtlasCircleMarker}
* @param {LiveAtlasCircleMarker} options LiveAtlasCircleMarker to calculate points for
* @param {Function} converter Function for projecting the points
* @param outline Whether the resulting points will be used in a shape without a fill color
* @returns Array of projected points
*/
export const getCirclePoints = (options: LiveAtlasCircleMarker, converter: Function, outline: boolean): LatLngExpression[] => {
const points = [];

View File

@ -21,11 +21,16 @@ import {useStore} from "@/store";
import MapProvider from "@/providers/MapProvider";
import DynmapMapProvider from "@/providers/DynmapMapProvider";
const expectedConfigVersion = 1;
const registeredProviders: Map<string, new (config: any) => MapProvider> = new Map();
const serverProviders: Map<string, MapProvider> = new Map();
const expectedConfigVersion = 1,
registeredProviders: Map<string, new (config: any) => MapProvider> = new Map(),
serverProviders: Map<string, MapProvider> = new Map();
/**
* Registers the given {@link MapProvider} with the given id
* Server entries in {@link LiveAtlasGlobalConfig} with the given id will use the given MapProvider
* @param {string} id The id
* @param {new (config: any) => MapProvider} provider The MapProvider
*/
export const registerMapProvider = (id: string, provider: new (config: any) => MapProvider) => {
if(registeredProviders.has(id)) {
throw new TypeError(`${id} is already registered`);
@ -34,10 +39,22 @@ export const registerMapProvider = (id: string, provider: new (config: any) => M
registeredProviders.set(id, provider);
}
/**
* Gets the MapProvider for the given server
* @param {string} server Name of the server
* @returns The MapProvider, if one exists
*/
export const getServerMapProvider = (server: string): MapProvider | undefined => {
return serverProviders.get(server);
}
/**
* Attempts to load server definitions from the provided config object
* @param {Object} config Config object to load server definitions from
* @returns Map of loaded servers
* @see {@link loadConfig}
* @private
*/
const loadLiveAtlasConfig = (config: any): Map<string, LiveAtlasServerDefinition> => {
const check = '\nCheck your server configuration in index.html is correct.',
result = new Map<string, LiveAtlasServerDefinition>();
@ -78,6 +95,12 @@ const loadLiveAtlasConfig = (config: any): Map<string, LiveAtlasServerDefinition
return result;
};
/**
* Attempts to load a Dynmap server definition from the given object
* @param {Object} config Config object to load from
* @see {@link loadConfig}
* @private
*/
const loadDefaultConfig = (config: DynmapUrlConfig): Map<string, LiveAtlasServerDefinition> => {
const check = '\nCheck your standalone/config.js file exists and is being loaded correctly.';
const result = new Map<string, LiveAtlasServerDefinition>();
@ -97,6 +120,14 @@ const loadDefaultConfig = (config: DynmapUrlConfig): Map<string, LiveAtlasServer
return result;
};
/**
* Attempts to load server definitions from the provided config object
* If no servers definitions are present in the object, an attempt will be made to load a Dynmap server definition from
* a global dynmap config object defined by standalone/config.js
* @param {Object} config Config object to load server definitions from
* @returns Map of loaded servers
* @private
*/
export const loadConfig = (config: LiveAtlasGlobalConfig): Map<string, LiveAtlasServerDefinition> => {
if (!config) {
throw new ConfigurationError(`No configuration found.\nCheck for any syntax errors in your configuration in index.html. Your browser console may contain additional information.`);

View File

@ -23,6 +23,19 @@ const navigationKeys = new Set<string>([
'End'
]);
/**
* Helper method for handling keyboard based selection, along with focus navigation within a set of HTML elements.
*
* The given {@link KeyboardEvent} will be checked for common navigation keys (currently arrow keys + home/end)
* and the appropriate {@link HTMLElement} in the provided array of elements will be focused. No focus changes will occur
* if none of the provided elements are currently focused
*
* The event will also be checked for an enter key press, and a click event will be simulated on the target element. The
* element does not need to be in the provided element array for this to occur
*
* @param {KeyboardEvent} e The event to handle
* @param {HTMLElement[]} elements The elements to consider for focusing
*/
export const handleKeyboardEvent = (e: KeyboardEvent, elements: HTMLElement[]) => {
if(!e.target) {
return;

View File

@ -25,7 +25,7 @@ const playerImageCache = new Map<string, HTMLImageElement>(),
playerImageQueue: PlayerImageQueueEntry[] = [];
/**
* Returns the corresponding pixel size for the given {@see LiveAtlasPlayerImageSize}
* Returns the corresponding pixel size for the given {@link LiveAtlasPlayerImageSize}
* @param {LiveAtlasPlayerImageSize} imageSize The image size to get the pixel size for
* @returns The pixel size
*/
@ -42,12 +42,12 @@ export const getImagePixelSize = (imageSize: LiveAtlasPlayerImageSize) => {
}
/**
* Creates an {@see HTMLImageElement} containing an image representing the given {@see LiveAtlasPlayer}
* at the given {@see LiveAtlasPlayerImageSize} and ensures it has loaded successfully
* Creates an {@link HTMLImageElement} containing an image representing the given {@link LiveAtlasPlayer}
* at the given {@link LiveAtlasPlayerImageSize} and ensures it has loaded successfully
*
* If an image has previously been loaded for the same player and image size, a cached copy of the image element
* will be returned; Otherwise an attempt will be made to load the player image from the URL specified by the current
* {@see LiveAtlasMapProvider}
* {@link LiveAtlasMapProvider}
*
* The number of concurrent image loads is limited and additional loads will be queued. If this method is called
* with the same player and image size multiple times, the load will only be queued once and the same element will be
@ -55,7 +55,8 @@ export const getImagePixelSize = (imageSize: LiveAtlasPlayerImageSize) => {
*
* @param {LiveAtlasPlayer} player The player to retrieve the image for
* @param {LiveAtlasPlayerImageSize} size The image size to retrieve
* @returns {Promise<HTMLImageElement>} A promise which will resolve to a {@see HTMLImageElement} with the loaded player
* @see {@link getDefaultPlayerImage}
* @returns {Promise<HTMLImageElement>} A promise which will resolve to a HTMLImageElement with the loaded player
* image as the src. The promise will reject if the image fails to load
*/
export const getPlayerImage = (player: LiveAtlasPlayer | string, size: LiveAtlasPlayerImageSize): Promise<HTMLImageElement> => {
@ -105,7 +106,8 @@ export const getPlayerImage = (player: LiveAtlasPlayer | string, size: LiveAtlas
/**
* Returns the default "Steve" player image. This image can be used as a placeholder whilst waiting for
* {@see getPlayerImage} to complete
* {@link getPlayerImage} to complete
* @see {@link getPlayerImage}
* @returns The default player image
*/
export const getDefaultPlayerImage = () => {
@ -131,7 +133,7 @@ const tickPlayerImageQueue = () => {
/**
* Clears the player image cache
* Future calls to {@see getPlayerImage} will result in fresh image loads
* Future calls to {@link getPlayerImage} will result in fresh image loads
*/
export const clearPlayerImageCache = () => {
playerImageCache.clear();

View File

@ -22,6 +22,12 @@ import {Coordinate, LiveAtlasLineMarker} from "@/index";
import {LatLngExpression} from "leaflet";
import {createPopup, tooltipOptions} from "@/util/paths";
/**
* Creates a {@link LiveAtlasPolyline} with the given options
* @param {LiveAtlasLineMarker} options Marker options
* @param {Function} converter Function for projecting the marker location onto the map
* @return The created LiveAtlasPolyline
*/
export const createLineLayer = (options: LiveAtlasLineMarker, converter: Function): LiveAtlasPolyline => {
const points = options.points.map(projectPointsMapCallback, converter),
line = new LiveAtlasPolyline(points, options);
@ -37,6 +43,13 @@ export const createLineLayer = (options: LiveAtlasLineMarker, converter: Functio
return line;
};
/**
* Updates or creates a {@link LiveAtlasPolyline} with the given options
* @param {?LiveAtlasPolyline} line Optional existing LiveAtlasPolyline
* @param {LiveAtlasLineMarker} options Marker options
* @param {Function} converter Function for projecting the marker location onto the map
* @returns The created or updated LiveAtlasPolyline
*/
export const updateLineLayer = (line: LiveAtlasPolyline | undefined, options: LiveAtlasLineMarker, converter: Function): LiveAtlasPolyline => {
if (!line) {
return createLineLayer(options, converter);
@ -62,6 +75,13 @@ export const updateLineLayer = (line: LiveAtlasPolyline | undefined, options: Li
return line;
}
/**
* Recursively applies the given function to the given array of {@link Coordinate}
* @param point
* @see {@link createAreaLayer}
* @see {@link updateAreaLayer}
* @private
*/
const projectPointsMapCallback = function(point: Coordinate): LatLngExpression {
if(Array.isArray(point)) {
return projectPointsMapCallback(point);
@ -71,6 +91,13 @@ const projectPointsMapCallback = function(point: Coordinate): LatLngExpression {
}
};
/**
* Calculates line points for the given individual x y and z arrays
* @param {number[]} x Array of x coordinates
* @param {[number, number]} y Array of y coordinates
* @param {number[]} z Array of z coordinates
* @returns Array of Coordinates
*/
export const getLinePoints = (x: number[], y: number[], z: number[]): Coordinate[] => {
const points = [];

View File

@ -53,6 +53,9 @@ let pendingUpdates: ComputedRef;
const updateHandlers: Set<LiveAtlasMarkerUpdateCallback> = new Set();
const setUpdateHandlers: { [key:string]: Set<LiveAtlasMarkerUpdateCallback>} = {};
/**
* Starts handling of pending marker updates
*/
export const startUpdateHandling = () => {
const store = useStore();
@ -65,6 +68,9 @@ export const startUpdateHandling = () => {
});
}
/**
* Stops handling of pending marker updates
*/
export const stopUpdateHandling = () => {
if(updateFrame) {
cancelAnimationFrame(updateFrame);
@ -72,14 +78,27 @@ export const stopUpdateHandling = () => {
}
}
/**
* Registers the given callback as a global handler for marker updates
* @param {LiveAtlasMarkerUpdateCallback} callback The callback
*/
export const registerUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback) => {
updateHandlers.add(callback);
}
/**
* Unregisters the given callback as a global handler for marker updates
* @param {LiveAtlasMarkerUpdateCallback} callback The callback
*/
export const unregisterUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback) => {
updateHandlers.delete(callback);
}
/**
* 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();
@ -88,6 +107,11 @@ export const registerSetUpdateHandler = (callback: LiveAtlasMarkerUpdateCallback
setUpdateHandlers[set].add(callback);
}
/**
* 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;
@ -96,6 +120,12 @@ export const unregisterSetUpdateHandler = (callback: LiveAtlasMarkerUpdateCallba
setUpdateHandlers[set].delete(callback);
}
/**
* 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);
@ -116,6 +146,16 @@ const handlePendingUpdates = async () => {
}
};
/**
* 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
*/
export const createMarkerLayer = (options: LiveAtlasMarker, converter: Function): Layer => {
switch(options.type) {
case LiveAtlasMarkerType.POINT:
@ -129,6 +169,17 @@ export const createMarkerLayer = (options: LiveAtlasMarker, converter: Function)
}
}
/**
* 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
*/
export const updateMarkerLayer = (marker: Layer | undefined, options: LiveAtlasMarker, converter: Function): Layer => {
switch(options.type) {
case LiveAtlasMarkerType.POINT:

View File

@ -24,11 +24,23 @@ export const tooltipOptions = {
interactive: false,
};
/**
* Determines if the 2 given arrays of {@link LatLngExpression} are equal by comparing the JSON serialised representations
* @param {LatLngExpression | LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][]} oldPoints Points to compare
* @param {LatLngExpression | LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][]} newPoints Other points to compare
* @return Whether both arrays of points are considered equal
*/
export const arePointsEqual = (oldPoints: LatLngExpression | LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][],
newPoints: LatLngExpression | LatLngExpression[] | LatLngExpression[][] | LatLngExpression[][][]) => {
return JSON.stringify(oldPoints) === JSON.stringify(newPoints);
}
/**
* Determines if the 2 given {@link PathOptions} are equal by comapring their properties
* @param {PathOptions} oldStyle PathOptions to compare
* @param {PathOptions} newStyle Other PathOptions to compare
* @return Whether both PathOptions are considered equal
*/
export const isStyleEqual = (oldStyle: PathOptions, newStyle: PathOptions) => {
return oldStyle && newStyle
&& (oldStyle.color === newStyle.color)
@ -38,6 +50,12 @@ export const isStyleEqual = (oldStyle: PathOptions, newStyle: PathOptions) => {
&& (oldStyle.fillOpacity === newStyle.fillOpacity)
}
/**
* Creates a popup element for the given marker
* @param {LiveAtlasPointMarker} options Marker options
* @param {string} className Classname to add to the popup element
* @returns {HTMLSpanElement} The marker element
*/
export const createPopup = (options: LiveAtlasPathMarker, className: string): HTMLElement => {
const popup = document.createElement('span');

View File

@ -14,12 +14,18 @@
* limitations under the License.
*/
import {LeafletMouseEvent, Marker} from "leaflet";
import {LeafletMouseEvent} from "leaflet";
import {GenericIcon} from "@/leaflet/icon/GenericIcon";
import {GenericMarker} from "@/leaflet/marker/GenericMarker";
import {LiveAtlasPointMarker} from "@/index";
export const createPointLayer = (options: LiveAtlasPointMarker, converter: Function): Marker => {
/**
* Creates a {@link GenericMarker} with the given options
* @param {LiveAtlasPointMarker} options Marker options
* @param {Function} converter Function for projecting the marker location onto the map
* @return The created GenericMarker
*/
export const createPointLayer = (options: LiveAtlasPointMarker, converter: Function): GenericMarker => {
const marker = new GenericMarker(converter(options.location), options);
marker.on('click', (e: LeafletMouseEvent) => {
@ -35,7 +41,14 @@ export const createPointLayer = (options: LiveAtlasPointMarker, converter: Funct
return marker;
};
export const updatePointLayer = (marker: Marker | undefined, options: LiveAtlasPointMarker, converter: Function): Marker => {
/**
* Updates or creates a {@link GenericMarker} with the given options
* @param {?GenericMarker} marker Optional existing GenericMarker to update
* @param {LiveAtlasPointMarker} options Marker options
* @param {Function} converter Function for projecting the marker location onto the map
* @returns The created or updated GenericMarker
*/
export const updatePointLayer = (marker: GenericMarker | undefined, options: LiveAtlasPointMarker, converter: Function): GenericMarker => {
if (!marker) {
return createPointLayer(options, converter);
}
@ -71,6 +84,12 @@ export const updatePointLayer = (marker: Marker | undefined, options: LiveAtlasP
return marker;
};
/**
* Creates a popup element for the given marker
* @param {LiveAtlasPointMarker} options Marker options
* @returns {HTMLSpanElement} The marker element
* @private
*/
const createPopup = (options: LiveAtlasPointMarker) => {
const popup = document.createElement('span');

View File

@ -21,6 +21,10 @@ const app = document.getElementById('app'),
splashErrorMessage = document.getElementById('splash__error-message'),
splashRetry = document.getElementById('splash__error-retry');
/**
* Shows the LiveAtlas splash screen, if it isn't already visible
* @param reset If true, any existing errors or retry counts will be removed
*/
export const showSplash = function(reset: boolean) {
if(!splash || !app) {
return;
@ -48,6 +52,10 @@ export const showSplash = function(reset: boolean) {
});
};
/**
* Hides the LiveAtlas splash screen, if it is visible
* The splash screen is not fully hidden immediately, as it has a CSS defined fade out animation
*/
export const hideSplash = () => {
if(!splash || !app) {
return;
@ -63,6 +71,16 @@ export const hideSplash = () => {
});
};
/**
* Displays the given error message on the splash screen
* If the splash screen is not currently visible {@link showSplash} should also be called
* @see {@link showSplash}
* @param {string} message The error message to display
* @param {boolean} fatal If true the loading spinner will be hidden to indicate a fatal error. This does not stop any
* ongoing processes the loading indicator was indicating
* @param {?number} attempts Optional number of previous retry attempts that occurred before the current error. If
* provided this will be displayed after the error message
*/
export const showSplashError = (message: string, fatal: boolean, attempts?: number) => {
if(splashError) {
splashError.setAttribute('aria-hidden', 'false');