@metoceanapi/wxtiles-leaflet

wxtiles

This is a project for weather data visualization. There are three main parts of the project:

  1. Splitter - a service that splits the datasets into tiles (PNG) and some metadata (JSON) served by a fileserver backend aka NGINX.
  2. WxTiles-mbox source code, npm @metoceanapi/wxtiles-mbox - a JS API providing work with metadata, dataset manager and an implementation of a Custom MapBox-gl-gs Layer for visualizing the tiles using Mapbox-gl-gs.
  3. WxTiles-leaflet source code, npm @metoceanapi/wxtiles-leaflet - a JS API providing work with metadata, dataset manager and an implementation of a Custom Leaflet Layer for visualizing the tiles using Leaflet.

API

APIs for Leaflet and Mapbox-gl-gs are similar in many ways. The difference is in framework-specific implementations of the Custom Source/Layer.

Usage and API documentation is mainly equal for both frameworks.

DOCS

Examples

  1. SimpleDemo.
  2. Animated blur parameter
  3. Mouse Interaction

Leaflet

import 'leaflet/dist/leaflet.css';
import L from 'leaflet';start();

/*
start();

/*

import { WxAPI } from '@metoceanapi/wxtiles-leaflet';

async func(){
// Get the API ready - should be ONE per application
// requestInit is used in every request to the server. Add your keys, credentials, mode, etc.
const wxapi = new WxAPI({ dataServerURL: 'https://tiles.metoceanapi.com/data/',
requestInit: { /* headers: new Headers([['x-api-key', 'key']]), */ } });

// Create a dataset manager (may be used for many variables-layers from this dataset)
const wxdatasetManager = await wxapi.createDatasetManager('gfs.global');

// Automatically gets a proper set of variable(s) from the dataset and composes northward or eastward components if needed
const variables = wxdatasetManager.checkCombineVariableIfVector('air.temperature.at-2m'); // 'wind.speed.eastward.at-10m' - Vector example

// create a layer
const leafletOptions: L.GridLayerOptions = { opacity: 1, attribution: 'WxTiles' };
const wxsource = new WxTileSource({ wxdatasetManager, variables }, leafletOptions);

// add the layer to the map
const map = L.map('map', { center: [0, 0], zoom: 2, zoomControl: true });
map.addLayer(wxsource);
await new Promise((done) => wxsource.once('load', done)); // highly recommended to await for the first load
}()

Change the time step

await wxsource.setTimeStep(1); // 1 - index of the time step in the dataset

or

await wxsource.setTimeStep('2020-01-01T00:00:00Z'); // '2020-01-01T00:00:00Z' - time step in the dataset

or

await wxsource.setTimeStep(2345323454); //  time in seconds since 1970-01-01T00:00:00Z

or

await wxsource.setTimeStep(new Date('2020-01-01T00:00:00Z')); // Date object

Update the style

await wxsource.updateCurrentStyleObject({ units: 'm/s', levels: undefined }); // set levels to undefined - to automatically calculate the levels from the dataset

Preload the time steps

// load the time step 10 to the cache but do not not render it
const prom = wxsource.preloadTime(10);
// do stuff asyncronously
// ...
await prom; // wait for the time step to finish loading
// now set the time step to 10
await wxsource.setTime(10); // will be fast rendered from the cache

Abort loading

const abortController = new AbortController();
console.log('setTime(5)');
const prom = wxsource.setTime(5, abortController);
abortController.abort(); // aborts the request
await prom; // await always !! even if aborted
console.log('aborted');

Get the current time step

const timeStep = wxsource.getTime();

read lon lat data

map.on('mousemove', (e) => {
if (!wxsource) return;
const pos = position(e); //
const tileInfo: WxTileInfo | undefined = wxsource.getLayerInfoAtLatLon(pos.wrap(), map);
if (tileInfo) {
console.log(tileInfo);
}
});

animated blur effect

(async function step(n: number = 0) {
await wxsource.updateCurrentStyleObject({ isolineText: false, blurRadius: ~~(10 * Math.sin(n / 500) + 10) }); // await always !!
requestAnimationFrame(step);
})();

more interactive - additional level and a bit of the red transparentness around the level made from current mouse position

await wxsource.updateCurrentStyleObject({ levels: undefined }); // reset levels if existed in the style
const levels = wxsource.getCurrentStyleObjectCopy().levels || []; // get current/default/any levels
// generate a new color map from the levels
const colMap: [number, string][] = levels.map((level) => [level, '#' + Math.random().toString(16).slice(2, 8) + 'ff']);
let busy = false;
map.on('mousemove', async (e) => {
if (!wxsource || busy) return;
busy = true;
const tileInfo: WxTileInfo | undefined = wxsource.getLayerInfoAtLatLon(position(e), map);
if (tileInfo) {
await wxsource.updateCurrentStyleObject({ colorMap: [...colMap, [tileInfo.inStyleUnits[0], '#ff000000']] });
onsole.log(tileInfo);
}
busy = false;
});

Generated using TypeDoc