@maptiler/weather
Version:
Weather layers for MapTiler Cloud and MapTiler SDK
384 lines (383 loc) • 13.9 kB
TypeScript
import { CustomLayerInterface, CustomRenderMethodInput, MapProjectionEvent, Map as MapSDK } from '@maptiler/sdk';
import { Extent } from 'ol/extent.js';
import { ColoringFragmentBase, MultiChannelGradientColoringFragment } from '../../core/ColoringFragment';
import { Tile, TileTextureSource } from '../../core/TileTextureSource';
import { TimeFrame, TimeFrameAnimation } from '../../core/TimeFrameAnimation';
import { GlobeTilesService } from '../../tiles/GlobeTilesService';
import { TileLayerOptions, TilePlacement, TileList } from './types';
import * as three from "three";
/**
* Special layer that can be added to MapTiler SDK's Map.
* Consists of multiple timeframes, every frame is a tile pyramid in a different moment in time.
* The individual frames are smoothly animated.
* Decoding of the data and their visual representation is configurable.
*/
declare class TileLayer extends TimeFrameAnimation<TileTextureSource> implements CustomLayerInterface {
id: string;
type: "custom";
renderingMode: "3d";
/**
* Instance of MapTiler SDK map
*/
protected map: MapSDK | null;
protected dataMinZoom: number;
protected dataMaxZoom: number;
/**
* Array of array of Tiles (plane geometry meshes)
*/
protected readonly slippyTiles: Array<Array<three.Mesh>>;
/**
* Renderer to render the tiles
*/
protected renderer: three.WebGLRenderer | null;
/**
* Camera used to render the tiles
*/
protected readonly camera: three.Camera;
/**
* Scene to add the tiles to
*/
protected readonly scene: three.Scene;
/**
* The shader material of the tiles (with uniforms such as textures, time, etc.)
* TODO: Fix the initialisation to get rid of the `!` operator
*/
private material;
/**
* The plane geometry used for all the tiles
*/
private geometry;
/**
* A TileGrid (from OL) that contains some tile logic such as mercator to index, etc.
*/
private tilegrid;
/**
* Extent as in OL
*/
private extent;
/**
* Indicated whether the the function `map.triggerRepaint()` should be called
* when the animation is paused.
*/
private repaintOnPausedAnimation;
/**
* Manages a pool of rawshadermaterial to reuse, rather cloning endlessly
*/
private materialPool;
private bluringNodePasses;
/**
* ratio to wich the extent is enlarged when using the method `.getVisibleExtent()`
*/
protected extentScale: number;
/**
* The event `"extentChanged"` is emitted when the intersection-over-union ration from the former extent to the new
* is below this.extentChangedThreshold
*/
private extentChangedThreshold;
private lastExtent;
private timeInterpolation;
protected isReady: boolean;
private defaultTexture;
private onMoveEndListener;
private onResizeListener;
private onMoveListener;
private onProjectionChangedListener;
private coloringFragments;
private multiChannelColoringFragment;
private loadLowerZoomLevels;
private interpolateTileEdge;
private flusher;
/**
* Globe related changes
*/
protected globeTilesService: GlobeTilesService;
protected threeWorldGroup: three.Group;
protected slippyTilesGroup: three.Group;
/**
* @param id Unique identifier of the layer in the map.
* @param options
* @param coloringFragments
* @param multiChannelColoringFragment
*/
constructor(id: string, options: TileLayerOptions | null, coloringFragments?: ColoringFragmentBase[] | null, multiChannelColoringFragment?: MultiChannelGradientColoringFragment | null);
/**
* TODO: Add description
*/
protected init(options: TileLayerOptions, coloringFragments?: ColoringFragmentBase[] | null, multiChannelColoringFragment?: MultiChannelGradientColoringFragment | null): void;
/**
* @description Event handler - callback when the window is resized.
*/
protected onResize(): void;
/**
* @description Event handler - callback when the map is moved.
*/
protected onMove(): void;
/**
* @description Event handler - called when the map movement ends.
*/
protected onMoveEnd(): void;
/**
* @description Event handler - called when projection is changed
*/
onProjectionChanged(event: MapProjectionEvent): void;
/**
* Remove the current tiles of the tile grid from the scene and reinstanciate them all
* (three.Mesh) based onthe arguments, then add them to the scene again.
* Note: The tils positions are not updated yet, this is performed by `.updateSlippyTile()`
* @param width
* @param height
*/
private updateSlippyTileGrid;
/**
* TODO: Add description
*/
private validateSource;
/**
* Adds another frame to the animation.
* @param time Time of the data in this frame. Should be unique.
* @param url URL to the tiles. Expected to have `{zxy}` placeholder to be dynamically replaced with `z/x/y` coordinates.
*/
addSource(time: number, url: string, loadedCallback?: ((tile: Tile, url?: string, error?: ErrorEvent | null) => void) | null): void;
/**
* Removes frame
*/
removeSource(time: number): void;
/**
* Get the Extent as defined in OL
* @param scale
* @returns
*/
getVisibleExtent(scale?: number): Extent | null;
/**
* Get the list of all the tiles wanted for this extent and from the min zoom to the max zoom.
* This is used to prevent updating tiles that are not in this list in `.updateSlippyTile()`
* @param currentZ
* @returns {TileList}
*/
getWantedTiles(currentZ: number, minZoom: number, maxZoom: number): TileList;
/**
* Changes the global opacity of the layer.
* Default is `1`
*
* @param opacity Opacity 0-1.
*/
setOpacity(opacity: number): void;
/**
* Method from CustomLayerInterface, called when the layer is added to the map
* @param map
* @param gl
*/
onAdd(map: MapSDK, gl: WebGLRenderingContext | WebGL2RenderingContext): void;
/**
* Method which should be override by the child class
* for additional logic which has to be done:
* - on adding the layer to the map
* - on mouseEnd event
*/
protected refresh(): void;
/**
* The method is called when the layer is removed from the map
* `CustomLayerInterface` method
*/
onRemove(_map: MapSDK, _gl: WebGLRenderingContext | WebGL2RenderingContext): void;
/**
* Remove some data allocated (not of the tiles)
*/
protected disposeObjects(): void;
/**
* Get the TilePlacement from a zxy
* @param source
* @param load
* @param z
* @param x
* @param y
* @param originalTileCoordinates
* @returns
*/
private getTilePlacement;
/**
* WARNING: Globe projection only
*
* Update the tiles textures
* TODO: Make mercator mode also use this method instead of `updateSlippyTiles`
*/
private updateTilesMaterials;
/**
* WARNING: Mercator projection only
*
* Update the tile's mesh position and size, as well each tile material uniforms (time, texture, etc.)
*
* @returns {void}
*/
protected updateSlippyTiles(): void;
/**
* TODO: Add description
*/
protected getTilesPair(frameA: TimeFrame<TileTextureSource>, frameB: TimeFrame<TileTextureSource>, tileId: string): {
tileA: TilePlacement;
tileB: TilePlacement;
} | null;
/**
* `CustomLayerInterface` method
* This is used to apply the map matrix to the local camera
*/
prerender(_gl: WebGLRenderingContext | WebGL2RenderingContext, options: CustomRenderMethodInput): void;
/**
* The reason for this method is to allow child classes to do some work during the prerender phase
*/
protected prerenderInternal(): void;
/**
* `CustomLayerInterface` method
* It is used to render the local tiles into the MapTiler SDK context
*/
render(_gl: WebGLRenderingContext | WebGL2RenderingContext, _options: CustomRenderMethodInput): void;
/**
* The reason for this method is to allow child classes to do some work during the render phase
* (after renderer state reset and before the actual rendering)
*/
protected renderInternal(): void;
/**
* Get layer image decoded value (decoded means on the real world interval such as provided [decode.min, decode.max])
* @param lng
* @param lat
* @param source
* @returns
*/
private pickFrame;
/**
* TODO: Add description
*/
private pickFrameBilinear;
/**
* Picks the best currently available values at the position.
*
* The values are read from the already loaded tiles at the current time.
*
* Return the interpolated array of decoded values
* of the same length as the number of specified coloring fragments.
*
* If the coloring fragments uses more channels (e.g. "rg"),
* the corresponding value is an array of `[r value, g value, sqrt(r^2 + g^2)]`.
*
* @param lng
* @param lat
* @returns Array of decoded interpolated values. In case of using a multi-channel coloring fragment, the returned value is an array where the first value is the value and the second is the category
*/
pick(lng: number, lat: number, options?: {
/**
* Enable bilinear interpolation if `true`, otherwise, the picking will be based on the nearest neighbor (NN) pixel.
* NN has less impact on performance because it requires less texture reading, so it is generaly faster. Bilinear is more precise
* and will retrieve values that are closer to what is being displayed (since tiles are rendered using a native-GPU bilinear method)
* Default: `false`
*/
bilinear?: boolean;
/**
* If `true`, the picking will be perfomed on the highest resolution tile available. If `false`, the picking is done on the tile currently showing on the map.
*/
highestRes?: boolean;
/**
* Will force the loading of the tile if it was not already cached.
* Usually unnecesary when the picking is done from hovering the pointer on the map, unless the option `.highRes` is `true`.
* Default: `false`.
*/
load?: boolean;
}): number[] | null;
/**
* The map is available only after the layer is attached to the map
* The method simplifies the access to the map object
*/
protected getMapOrThrow: () => MapSDK;
/**
* The renderer is available only after the layer is attached to the map
* The method simplifies the access to the renderer object
*/
protected getRendererOrThrow: () => three.WebGLRenderer;
/**
* The method simplifies the access to the triggerRepaint method
*/
forceRepaint(): void;
/**
* Get the current mixed image as a ImageData, meaning with pixel data, width, height and number of channels
* Used by: Weather Plus
* @param options.zxy The tile ID
* @param options.blurKernel Size of the bluring kernel
* @param options.outputSize Size of the outpout image (-1 means same as input). Note that the bluring is applied on an image of this size.
* @returns ImageData | null
*/
computeCurrentMixedImage({ zxy, blurKernel, outputSize, channel, }: {
zxy?: string;
blurKernel?: number;
outputSize?: number;
channel?: string;
}): ImageData | null;
/**
* Enables data interpolation between keyframes when true. Only shows keyframe data when false.
* @param ti
*/
setTimeInterpolation(ti: boolean): void;
/**
* Enable smoothing category color when true. Hard edge between categories when false.
* This seeting applies only to TileLayers using MultiChannelGradientColoringFragment
* as the other types of oloring fragment do not use categories.
* @param cst
*/
setCategorySmoothTransition(cst: boolean): void;
/**
* If `true`, enables the local smoothing
* @param s
*/
setLocalSmoothing(s: boolean): void;
/**
* Defines the size of the smoothing kernel
* @param d
*/
setMaxSmoothingDistance(d: number): void;
/**
* Defines by what factor the smoothing kernel size is reduced with increasing zoom level
* @param f
*/
setSmoothingDistanceDecayFactor(f: number): void;
/**
* Get whether or not the frames continues to rendered on a paused animation
* @returns
*/
getRepaintOnPausedAnimation(): boolean;
/**
* If `true`, even the paused animation is rendered up to 60 times
* per seconds. If `false`, the rendering is paused when the animation is paused.
* Pausing the animation has side effects:
* - it lowers energy consumtion
* - it prevents overheating
* - it pauses time-independant annimation (arrows, particles)
* @param r
*/
setRepaintOnPausedAnimation(r: boolean): void;
/**
* Wrapping telemetry registration with protected method to allow registration of modules which extends this class
*/
protected registerTelemetry(map: MapSDK): void;
}
export { TileLayer };
/**
* TODO:
* - Add explanation
* - Export to separate file, somehow
*/
interface ImageData {
/**
* The pixel data
*/
data: Uint8Array;
/**
* The number of channels of the image (example: if image is RGBA then channels is 4)
*/
channels: number;
/**
* Width of the image
*/
width: number;
/**
* Height of the image
*/
height: number;
}