1. Mapbox或Maplibre加载风场
所需的文件 mapbox-wind.js、wind-core.js、wind-gl-core.js 放在同一目录下
mapbox-wind.js
// mapbox-wind.js
import { WindCore, defaultOptions, isArray, formatData, assign } from './wind-core';
export { Field } from './wind-core';
import * as maplibregl from 'maplibre-gl';
import { ScalarFill as ScalarFill$1, getEye, fp64LowPart, WindParticles } from './wind-gl-core';
function removeDomNode(node) {
if (!node) {
return null;
}
if (node.parentNode) {
node.parentNode.removeChild(node);
}
return node;
}
class Overlay {
constructor(id, options = {}) {
if (!id) {
throw Error("layer id must be specified");
}
this.id = id;
this.options = options;
this.canvas = null;
this.canvas2 = null;
this.devicePixelRatio = this.options.devicePixelRatio || (window.devicePixelRatio || window.screen.deviceXDPI / window.screen.logicalXDPI);
this.render = this.render.bind(this);
this.type = "custom";
this.renderingMode = "2d";
}
onAdd(map) {
this.setMap(map);
this.canvas = this.initialize();
if (this.options.doubleBuffer) {
this.canvas2 = this.initialize();
}
}
resizeCanvas(canvas) {
const mapboxCanvas = this.map.getCanvas();
const { width, height } = this.map.transform;
const pixel = this.devicePixelRatio;
canvas.width = width * pixel;
canvas.height = height * pixel;
canvas.style.width = mapboxCanvas.style.width;
canvas.style.height = mapboxCanvas.style.height;
}
initialize() {
const canvasContainer = this.map.getCanvasContainer();
const mapboxCanvas = this.map.getCanvas();
const canvasOverlay = document.createElement("canvas");
const { width, height } = this.map.transform;
const pixel = this.devicePixelRatio;
canvasOverlay.width = width * pixel;
canvasOverlay.height = height * pixel;
canvasOverlay.style.position = "absolute";
canvasOverlay.className = "mapbox-overlay-canvas";
canvasOverlay.style.width = mapboxCanvas.style.width;
canvasOverlay.style.height = mapboxCanvas.style.height;
canvasContainer.appendChild(canvasOverlay);
return canvasOverlay;
}
render() {
}
project(coordinates) {
if (this.map !== void 0) {
const lnglat = this.map.project(new maplibregl.LngLat(coordinates[0], coordinates[1]));
const x = lnglat.x;
const y = lnglat.y;
return [
x * this.devicePixelRatio,
y * this.devicePixelRatio
];
}
return coordinates;
}
unproject(pixel) {
if (this.map !== void 0) {
const lnglat = this.map.unproject(new maplibregl.Point(pixel[0], pixel[1]));
return [lnglat.lng, lnglat.lat];
}
return pixel;
}
intersectsCoordinate(coordinate) {
var _a, _b;
const bounds = this.map.getBounds();
const latRange = (_b = (_a = this.map) == null ? void 0 : _a.transform) == null ? void 0 : _b.latRange;
if (latRange) {
if (coordinate[1] > latRange[1] || coordinate[1] < latRange[0])
return false;
}
return bounds.contains(new maplibregl.LngLat(coordinate[0], coordinate[1]));
}
clear() {
if (this.canvas) {
const ctx = this.canvas.getContext("2d");
ctx && ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
if (this.canvas2) {
const ctx = this.canvas2.getContext("2d");
ctx && ctx.clearRect(0, 0, this.canvas2.width, this.canvas2.height);
}
}
setMap(map) {
this.map = map;
return this;
}
getMap() {
return this.map;
}
addTo(map) {
this.onAdd(map);
}
remove() {
if (this.canvas) {
removeDomNode(this.canvas);
this.canvas = null;
}
if (this.canvas2) {
removeDomNode(this.canvas2);
this.canvas2 = null;
}
}
}
function getCoords$1([lng, lat]) {
const mercatorCoordinate = maplibregl.MercatorCoordinate.fromLngLat({
lng,
lat
});
return [mercatorCoordinate.x, mercatorCoordinate.y];
}
class ScalarFill {
constructor(id, data, options) {
this.id = id;
this.type = "custom";
this.renderingMode = "3d";
this.options = {
...options || {}
};
this.data = data;
this.handleZoom = this.handleZoom.bind(this);
}
handleZoom() {
if (this.scalarFill) {
this.scalarFill.handleZoom();
}
}
initialize() {
if (!this.scalarFill && this.gl) {
this.scalarFill = new ScalarFill$1(this.gl, {
opacity: this.options.opacity,
renderForm: this.options.renderForm,
styleSpec: this.options.styleSpec,
displayRange: this.options.displayRange,
mappingRange: this.options.mappingRange,
widthSegments: this.options.widthSegments,
heightSegments: this.options.heightSegments,
wireframe: this.options.wireframe,
createPlaneBuffer: this.options.createPlaneBuffer,
getZoom: () => this.map.getZoom(),
triggerRepaint: () => {
this.map.triggerRepaint();
},
injectShaderModules: {
"#modules-transformZ": `
const float MATH_PI = 3.141592653589793;
const float earthRadius = 6371008.8;
const float earthCircumfrence = 2.0 * MATH_PI * earthRadius;
float latFromMercatorY(float y) {
float y2 = 180.0 - y * 360.0;
return 360.0 / MATH_PI * atan(exp(y2 * MATH_PI / 180.0)) - 90.0;
}
float circumferenceAtLatitude(float latitude) {
return earthCircumfrence * cos(latitude * MATH_PI / 180.0);
}
float mercatorScale(float lat) {
return 1.0 / cos(lat * MATH_PI / 180.0);
}
float transformZ(float value, vec3 pos) {
float mercatorY = pos.y;
// float scale = circumferenceAtLatitude(latFromMercatorY(mercatorY));
float scale = earthCircumfrence * mercatorScale(latFromMercatorY(mercatorY));
return value / scale;
}
`,
"#modules-project": `
gl_Position = u_matrix * vec4(pos.xy + vec2(u_offset, 0.0), pos.z + z, pos.w);
gl_Position.w += u_cameraEye.w;
`
}
});
this.scalarFill.getMercatorCoordinate = getCoords$1;
this.map.on("zoom", this.handleZoom);
}
if (this.data) {
this.setData(this.data);
}
}
updateOptions(options) {
this.options = {
...this.options,
...options || {}
};
if (this.scalarFill) {
this.scalarFill.updateOptions(options);
}
}
onAdd(map, gl) {
this.gl = gl;
this.map = map;
if (this.map) {
this.initialize();
}
}
setData(data) {
return new Promise((resolve, reject) => {
this.data = data;
if (this.data && this.scalarFill) {
this.scalarFill.setData(this.data, (status) => {
if (status) {
resolve(true);
} else {
reject(false);
}
});
} else {
resolve(false);
}
});
}
onRemove(map) {
if (this.scalarFill) {
this.scalarFill.destroyed();
this.scalarFill = null;
}
delete this.gl;
delete this.map;
map.off("zoom", this.handleZoom);
}
getWrappedWorlds() {
const result = [0];
if (this.options.wrapX) {
const { width, height } = this.map.transform;
const utl = this.map.transform.pointCoordinate(new maplibregl.Point(0, 0));
const utr = this.map.transform.pointCoordinate(
new maplibregl.Point(width, 0)
);
const ubl = this.map.transform.pointCoordinate(
new maplibregl.Point(width, height)
);
const ubr = this.map.transform.pointCoordinate(
new maplibregl.Point(0, height)
);
const w0 = Math.floor(Math.min(utl.x, utr.x, ubl.x, ubr.x));
const w1 = Math.floor(Math.max(utl.x, utr.x, ubl.x, ubr.x));
const extraWorldCopy = 1;
for (let w = w0 - extraWorldCopy; w <= w1 + extraWorldCopy; w++) {
if (w === 0) {
continue;
}
result.push(w);
}
}
return result;
}
render(gl, matrix) {
const cameraEye = getEye(matrix);
const cameraEye64Low = cameraEye.map((item) => fp64LowPart(item));
if (this.data && this.scalarFill) {
const worlds = this.getWrappedWorlds();
for (let i = 0; i < worlds.length; i++) {
this.scalarFill.render(matrix, worlds[i], {
cameraEye,
cameraEye64Low
});
}
}
}
}
function getCoords([lng, lat]) {
const mercatorCoordinate = maplibregl.MercatorCoordinate.fromLngLat({
lng,
lat
});
return [mercatorCoordinate.x, mercatorCoordinate.y];
}
class Particles {
constructor(id, data, options) {
this.id = id;
this.type = "custom";
this.renderingMode = "2d";
this.options = {
...options || {}
};
this.data = data;
this.resize = this.resize.bind(this);
this.handleZoom = this.handleZoom.bind(this);
this.handleMovestart = this.handleMovestart.bind(this);
this.handleMoveend = this.handleMoveend.bind(this);
}
updateOptions(options) {
this.options = {
...this.options,
...options || {}
};
if (this.layer) {
this.layer.updateOptions(options);
}
}
handleZoom() {
if (this.layer) {
this.layer.handleZoom();
}
}
resize() {
if (this.layer) {
this.layer.resize();
}
}
handleMovestart() {
if (this.layer) {
this.layer.handleMovestart();
}
}
handleMoveend() {
if (this.layer) {
this.layer.handleMoveend();
}
}
initialize() {
if (!this.layer && this.gl) {
this.layer = new WindParticles(this.gl, {
getZoom: () => this.map.getZoom(),
triggerRepaint: () => {
this.map.triggerRepaint();
},
getExtent: () => {
const bounds = this.map.getBounds().toArray();
let xmin = bounds[0][0];
const ymin = bounds[0][1];
let xmax = bounds[1][0];
const ymax = bounds[1][1];
const worlds = this.getWrappedWorlds();
if (worlds.length > 1) {
xmin = -180;
xmax = 180;
} else {
if (xmin < -180) {
xmin = -180;
}
if (xmax > 180) {
xmax = 180;
}
}
const p0 = maplibregl.MercatorCoordinate.fromLngLat(
new maplibregl.LngLat(xmin, ymax)
);
const p1 = maplibregl.MercatorCoordinate.fromLngLat(
new maplibregl.LngLat(xmax, ymin)
);
return [p0.x, p0.y, p1.x, p1.y];
},
getSize: () => {
return [
this.map.transform.size.x,
this.map.transform.size.y
];
},
interacting: () => {
return !this.map.painter.options.moving && !this.map.painter.options.rotating && !this.map.painter.options.zooming;
},
getWorlds: () => this.getWrappedWorlds(),
...this.options
});
this.layer.getMercatorCoordinate = getCoords;
this.map.on("zoom", this.handleZoom);
this.map.on("movestart", this.handleMovestart);
this.map.on("resize", this.resize);
this.map.on("moveend", this.handleMoveend);
}
if (this.data) {
this.setData(this.data);
}
}
onAdd(map, gl) {
this.gl = gl;
this.map = map;
if (this.map) {
this.initialize();
}
}
setData(data) {
return new Promise((resolve, reject) => {
this.data = data;
if (this.data && this.layer) {
this.layer.setData(this.data, (status) => {
if (status) {
resolve(true);
} else {
reject(false);
}
});
} else {
resolve(false);
}
});
}
onRemove(map) {
if (this.layer) {
this.layer.destroyed();
this.layer = null;
}
map.off("zoom", this.handleZoom);
map.off("movestart", this.handleMovestart);
map.off("resize", this.resize);
map.off("moveend", this.handleMoveend);
delete this.gl;
delete this.map;
}
getWrappedWorlds() {
const result = [0];
if (this.options.wrapX) {
const { width, height } = this.map.transform;
const utl = this.map.transform.pointCoordinate(new maplibregl.Point(0, 0));
const utr = this.map.transform.pointCoordinate(
new maplibregl.Point(width, 0)
);
const ubl = this.map.transform.pointCoordinate(
new maplibregl.Point(width, height)
);
const ubr = this.map.transform.pointCoordinate(
new maplibregl.Point(0, height)
);
const w0 = Math.floor(Math.min(utl.x, utr.x, ubl.x, ubr.x));
const w1 = Math.floor(Math.max(utl.x, utr.x, ubl.x, ubr.x));
const extraWorldCopy = 0;
for (let w = w0 - extraWorldCopy; w <= w1 + extraWorldCopy; w++) {
if (w === 0) {
continue;
}
result.push(w);
}
}
return result;
}
prerender(gl, matrix) {
if (this.data && this.layer) {
this.layer.prerender(matrix);
}
}
render(gl, matrix) {
if (this.data && this.layer) {
this.layer.render(matrix);
}
}
}
const defaultConfig = {
doubleBuffer: false,
windOptions: defaultOptions
};
class WindLayer extends Overlay {
constructor(id, data, options = {}) {
super(id, { ...defaultConfig, ...options });
this.pickWindOptions();
if (data) {
this.setData(data, options.fieldOptions);
}
this.stop = this.stop.bind(this);
this.render = this.render.bind(this);
this.handleResize = this.handleResize.bind(this);
}
onAdd(map) {
super.onAdd(map);
if (!this.map) {
throw new Error("map is null");
}
if (this.canvas !== null) {
this.render();
this.registerEvents();
}
}
handleResize() {
if (this.canvas) {
this.resizeCanvas(this.canvas);
}
this.render();
}
registerEvents() {
this.map.on("resize", this.handleResize);
this.map.on("movestart", this.stop);
this.map.on("moveend", this.render);
this.map.on("zoomstart", this.stop);
this.map.on("zoomend", this.render);
this.map.on("rotatestart", this.stop);
this.map.on("rotateend", this.render);
this.map.on("pitchstart", this.stop);
this.map.on("pitchend", this.render);
}
unregisterEvents() {
this.map.off("resize", this.handleResize);
this.map.off("movestart", this.stop);
this.map.off("moveend", this.render);
this.map.off("zoomstart", this.stop);
this.map.off("zoomend", this.render);
this.map.off("rotatestart", this.stop);
this.map.off("rotateend", this.render);
this.map.off("pitchstart", this.stop);
this.map.off("pitchend", this.render);
}
stop() {
if (this.wind) {
this.wind.clearCanvas();
}
}
render() {
if (!this.map) {
return;
}
const opt = this.getWindOptions();
if (!this.wind && this.map && this.canvas !== null) {
const ctx = this.canvas.getContext("2d");
if (!ctx) {
console.error("create canvas context failed");
return;
}
const data = this.getData();
this.wind = new WindCore(ctx, opt, data);
this.wind.project = this.project.bind(this);
this.wind.unproject = this.unproject.bind(this);
this.wind.intersectsCoordinate = this.intersectsCoordinate.bind(this);
this.wind.postrender = () => {
};
}
this.wind.prerender();
this.wind.render();
}
remove() {
super.remove();
if (this.wind) {
this.wind.stop();
}
this.unregisterEvents();
}
pickWindOptions() {
Object.keys(defaultOptions).forEach((key) => {
if (this.options && key in this.options) {
if (this.options.windOptions === void 0) {
this.options.windOptions = {};
}
this.options.windOptions[key] = this.options[key];
}
});
}
getData() {
return this.field;
}
setData(data, options = {}) {
var _a;
if (data && data.checkFields && data.checkFields()) {
this.field = data;
} else if (isArray(data)) {
this.field = formatData(data, options);
} else {
console.error("Illegal data");
}
if (this.field) {
(_a = this == null ? void 0 : this.wind) == null ? void 0 : _a.updateData(this.field);
}
return this;
}
setWindOptions(options) {
const beforeOptions = this.options.windOptions || {};
this.options = assign(this.options, {
windOptions: assign(beforeOptions, options || {})
});
if (this.wind) {
const windOptions = this.options.windOptions;
this.wind.setOptions(windOptions);
this.wind.prerender();
}
}
getWindOptions() {
return this.options.windOptions || {};
}
}
export { Particles, ScalarFill, WindLayer, WindLayer as default };
//# sourceMappingURL=mapbox-wind.esm.js.map
wind-core.js
// wind-core.js
const hasOwnProperty = Object.prototype.hasOwnProperty;
const symToStringTag = typeof Symbol !== "undefined" ? Symbol.toStringTag : void 0;
function baseGetTag(value) {
if (value === null) {
return value === void 0 ? "[object Undefined]" : "[object Null]";
}
if (!(symToStringTag && symToStringTag in Object(value))) {
return toString.call(value);
}
const isOwn = hasOwnProperty.call(value, symToStringTag);
const tag = value[symToStringTag];
let unmasked = false;
try {
value[symToStringTag] = void 0;
unmasked = true;
} catch (e) {
}
const result = Object.prototype.toString.call(value);
if (unmasked) {
if (isOwn) {
value[symToStringTag] = tag;
} else {
delete value[symToStringTag];
}
}
return result;
}
function TypeOf(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}
function isFunction(value) {
if (!isObject(value)) {
return false;
}
const tag = baseGetTag(value);
return tag === "[object Function]" || tag === "[object AsyncFunction]" || tag === "[object GeneratorFunction]" || tag === "[object Proxy]";
}
function isObject(value) {
const type = typeof value;
return value !== null && (type === "object" || type === "function");
}
function isDate(val) {
return Object.prototype.toString.call(val) === "[object Date]";
}
function isArrayBuffer(val) {
return Object.prototype.toString.call(val) === "[object ArrayBuffer]";
}
function isString(value) {
if (value == null) {
return false;
}
return typeof value === "string" || value.constructor !== null && value.constructor === String;
}
function isNumber(value) {
return Object.prototype.toString.call(value) === "[object Number]" && !isNaN(value);
}
function isEmpty(object) {
let property;
for (property in object) {
return false;
}
return !property;
}
function isNull(obj) {
return obj == null;
}
function isArray(arr) {
return Array.isArray(arr);
}
function assign(target, ...sources) {
return Object.assign(target, ...sources);
}
function warnLog(msg, n) {
console.warn(`${n || "wind-layer"}: ${msg}`);
}
const warnings = {};
function warnOnce(namespaces, msg) {
if (!warnings[msg]) {
warnLog(msg, namespaces);
warnings[msg] = true;
}
}
function floorMod(a, n) {
return a - n * Math.floor(a / n);
}
function isValide(val) {
return val !== void 0 && val !== null && !isNaN(val);
}
function formatData(data, options = {}) {
let uComp = void 0;
let vComp = void 0;
data.forEach(function(record) {
switch (record.header.parameterCategory + "," + record.header.parameterNumber) {
case "1,2":
case "2,2":
uComp = record;
break;
case "1,3":
case "2,3":
vComp = record;
break;
}
});
if (!vComp || !uComp) {
return void 0;
}
const header = uComp.header;
const vectorField = new Field({
xmin: header.lo1,
ymin: header.la1,
xmax: header.lo2,
ymax: header.la2,
deltaX: header.dx,
deltaY: header.dy,
cols: header.nx,
rows: header.ny,
us: uComp.data,
vs: vComp.data,
...options
});
return vectorField;
}
function createCanvas(width, height, retina, Canvas) {
if (typeof document !== "undefined") {
const canvas = document.createElement("canvas");
canvas.width = width * retina;
canvas.height = height * retina;
return canvas;
} else {
return new Canvas(width * retina, height * retina);
}
}
function removeDomNode(node) {
if (!node) {
return null;
}
if (node.parentNode) {
node.parentNode.removeChild(node);
}
return node;
}
const keyword = /(\D+)/;
const hex = /^#([a-f0-9]{6})([a-f0-9]{2})?$/i;
const rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
const colorNames = {
aliceblue: [240, 248, 255],
antiquewhite: [250, 235, 215],
aqua: [0, 255, 255],
aquamarine: [127, 255, 212],
azure: [240, 255, 255],
beige: [245, 245, 220],
bisque: [255, 228, 196],
black: [0, 0, 0],
blanchedalmond: [255, 235, 205],
blue: [0, 0, 255],
blueviolet: [138, 43, 226],
brown: [165, 42, 42],
burlywood: [222, 184, 135],
cadetblue: [95, 158, 160],
chartreuse: [127, 255, 0],
chocolate: [210, 105, 30],
coral: [255, 127, 80],
cornflowerblue: [100, 149, 237],
cornsilk: [255, 248, 220],
crimson: [220, 20, 60],
cyan: [0, 255, 255],
darkblue: [0, 0, 139],
darkcyan: [0, 139, 139],
darkgoldenrod: [184, 134, 11],
darkgray: [169, 169, 169],
darkgreen: [0, 100, 0],
darkgrey: [169, 169, 169],
darkkhaki: [189, 183, 107],
darkmagenta: [139, 0, 139],
darkolivegreen: [85, 107, 47],
darkorange: [255, 140, 0],
darkorchid: [153, 50, 204],
darkred: [139, 0, 0],
darksalmon: [233, 150, 122],
darkseagreen: [143, 188, 143],
darkslateblue: [72, 61, 139],
darkslategray: [47, 79, 79],
darkslategrey: [47, 79, 79],
darkturquoise: [0, 206, 209],
darkviolet: [148, 0, 211],
deeppink: [255, 20, 147],
deepskyblue: [0, 191, 255],
dimgray: [105, 105, 105],
dimgrey: [105, 105, 105],
dodgerblue: [30, 144, 255],
firebrick: [178, 34, 34],
floralwhite: [255, 250, 240],
forestgreen: [34, 139, 34],
fuchsia: [255, 0, 255],
gainsboro: [220, 220, 220],
ghostwhite: [248, 248, 255],
gold: [255, 215, 0],
goldenrod: [218, 165, 32],
gray: [128, 128, 128],
green: [0, 128, 0],
greenyellow: [173, 255, 47],
grey: [128, 128, 128],
honeydew: [240, 255, 240],
hotpink: [255, 105, 180],
indianred: [205, 92, 92],
indigo: [75, 0, 130],
ivory: [255, 255, 240],
khaki: [240, 230, 140],
lavender: [230, 230, 250],
lavenderblush: [255, 240, 245],
lawngreen: [124, 252, 0],
lemonchiffon: [255, 250, 205],
lightblue: [173, 216, 230],
lightcoral: [240, 128, 128],
lightcyan: [224, 255, 255],
lightgoldenrodyellow: [250, 250, 210],
lightgray: [211, 211, 211],
lightgreen: [144, 238, 144],
lightgrey: [211, 211, 211],
lightpink: [255, 182, 193],
lightsalmon: [255, 160, 122],
lightseagreen: [32, 178, 170],
lightskyblue: [135, 206, 250],
lightslategray: [119, 136, 153],
lightslategrey: [119, 136, 153],
lightsteelblue: [176, 196, 222],
lightyellow: [255, 255, 224],
lime: [0, 255, 0],
limegreen: [50, 205, 50],
linen: [250, 240, 230],
magenta: [255, 0, 255],
maroon: [128, 0, 0],
mediumaquamarine: [102, 205, 170],
mediumblue: [0, 0, 205],
mediumorchid: [186, 85, 211],
mediumpurple: [147, 112, 219],
mediumseagreen: [60, 179, 113],
mediumslateblue: [123, 104, 238],
mediumspringgreen: [0, 250, 154],
mediumturquoise: [72, 209, 204],
mediumvioletred: [199, 21, 133],
midnightblue: [25, 25, 112],
mintcream: [245, 255, 250],
mistyrose: [255, 228, 225],
moccasin: [255, 228, 181],
navajowhite: [255, 222, 173],
navy: [0, 0, 128],
oldlace: [253, 245, 230],
olive: [128, 128, 0],
olivedrab: [107, 142, 35],
orange: [255, 165, 0],
orangered: [255, 69, 0],
orchid: [218, 112, 214],
palegoldenrod: [238, 232, 170],
palegreen: [152, 251, 152],
paleturquoise: [175, 238, 238],
palevioletred: [219, 112, 147],
papayawhip: [255, 239, 213],
peachpuff: [255, 218, 185],
peru: [205, 133, 63],
pink: [255, 192, 203],
plum: [221, 160, 221],
powderblue: [176, 224, 230],
purple: [128, 0, 128],
rebeccapurple: [102, 51, 153],
red: [255, 0, 0],
rosybrown: [188, 143, 143],
royalblue: [65, 105, 225],
saddlebrown: [139, 69, 19],
salmon: [250, 128, 114],
sandybrown: [244, 164, 96],
seagreen: [46, 139, 87],
seashell: [255, 245, 238],
sienna: [160, 82, 45],
silver: [192, 192, 192],
skyblue: [135, 206, 235],
slateblue: [106, 90, 205],
slategray: [112, 128, 144],
slategrey: [112, 128, 144],
snow: [255, 250, 250],
springgreen: [0, 255, 127],
steelblue: [70, 130, 180],
tan: [210, 180, 140],
teal: [0, 128, 128],
thistle: [216, 191, 216],
tomato: [255, 99, 71],
turquoise: [64, 224, 208],
violet: [238, 130, 238],
wheat: [245, 222, 179],
white: [255, 255, 255],
whitesmoke: [245, 245, 245],
yellow: [255, 255, 0],
yellowgreen: [154, 205, 50]
};
function getColor(string) {
let rgb = [];
if (string.match(hex)) {
let match = string.match(hex);
if (match !== null) {
match = match[1];
for (let i = 0; i < 3; i++) {
const i2 = i * 2;
rgb[i] = parseInt(match.slice(i2, i2 + 2), 16);
}
rgb[3] = 1;
}
} else if (string.match(rgba)) {
const match = string.match(rgba);
for (let i = 0; i < 3; i++) {
rgb[i] = parseInt(match[i + 1], 0);
}
if (match[4]) {
rgb[3] = parseFloat(match[4]);
} else {
rgb[3] = 1;
}
} else if (string.match(keyword)) {
const match = string.match(keyword);
if (match[1] === "transparent") {
return [0, 0, 0, 0];
}
rgb = colorNames[match[1]];
if (!rgb) {
return null;
}
rgb[3] = 1;
return rgb;
} else {
return null;
}
return rgb;
}
class Vector {
constructor(u, v) {
this.u = u;
this.v = v;
this.m = this.magnitude();
}
magnitude() {
return Math.sqrt(this.u ** 2 + this.v ** 2);
}
directionTo() {
const verticalAngle = Math.atan2(this.u, this.v);
let inDegrees = verticalAngle * (180 / Math.PI);
if (inDegrees < 0) {
inDegrees += 360;
}
return inDegrees;
}
directionFrom() {
const a = this.directionTo();
return (a + 180) % 360;
}
}
class Field {
constructor(params) {
this.grid = [];
this.xmin = params.xmin;
this.xmax = params.xmax;
this.ymin = params.ymin;
this.ymax = params.ymax;
this.cols = params.cols;
this.rows = params.rows;
this.us = params.us;
this.vs = params.vs;
this.deltaX = params.deltaX;
this.deltaY = params.deltaY;
this.flipY = Boolean(params.flipY);
this.ymin = Math.min(params.ymax, params.ymin);
this.ymax = Math.max(params.ymax, params.ymin);
if (!(this.deltaY < 0 && this.ymin < this.ymax)) {
if (params.flipY === void 0) {
this.flipY = true;
}
console.warn("[wind-core]: The data is flipY");
}
this.isFields = true;
const cols = Math.ceil((this.xmax - this.xmin) / params.deltaX);
const rows = Math.ceil((this.ymax - this.ymin) / params.deltaY);
if (cols !== this.cols || rows !== this.rows) {
console.warn("[wind-core]: The data grid not equal");
}
this.isContinuous = Math.floor(this.cols * params.deltaX) >= 360;
this.translateX = "translateX" in params ? params.translateX : this.xmax > 180;
if ("wrappedX" in params) {
warnOnce("[wind-core]: ", "`wrappedX` namespace will deprecated please use `translateX` instead\uFF01");
}
this.wrapX = Boolean(params.wrapX);
this.grid = this.buildGrid();
this.range = this.calculateRange();
}
buildGrid() {
let grid = [];
let p = 0;
const { rows, cols, us, vs } = this;
for (let j = 0; j < rows; j++) {
const row = [];
for (let i = 0; i < cols; i++, p++) {
let u = us[p];
let v = vs[p];
let valid = this.isValid(u) && this.isValid(v);
row[i] = valid ? new Vector(u, v) : null;
}
if (this.isContinuous) {
row.push(row[0]);
}
grid[j] = row;
}
return grid;
}
release() {
this.grid = [];
}
extent() {
return [
this.xmin,
this.ymin,
this.xmax,
this.ymax
];
}
bilinearInterpolateVector(x, y, g00, g10, g01, g11) {
const rx = 1 - x;
const ry = 1 - y;
const a = rx * ry;
const b = x * ry;
const c = rx * y;
const d = x * y;
const u = g00.u * a + g10.u * b + g01.u * c + g11.u * d;
const v = g00.v * a + g10.v * b + g01.v * c + g11.v * d;
return new Vector(u, v);
}
calculateRange() {
if (!this.grid || !this.grid[0])
return;
const rows = this.grid.length;
const cols = this.grid[0].length;
let min;
let max;
for (let j = 0; j < rows; j++) {
for (let i = 0; i < cols; i++) {
const vec = this.grid[j][i];
if (vec !== null) {
const val = vec.m || vec.magnitude();
if (min === void 0) {
min = val;
} else if (max === void 0) {
max = val;
min = Math.min(min, max);
max = Math.max(min, max);
} else {
min = Math.min(val, min);
max = Math.max(val, max);
}
}
}
}
return [min, max];
}
isValid(x) {
return x !== null && x !== void 0;
}
getWrappedLongitudes() {
let xmin = this.xmin;
let xmax = this.xmax;
if (this.translateX) {
if (this.isContinuous) {
xmin = -180;
xmax = 180;
} else {
xmax = this.xmax - 360;
xmin = this.xmin - 360;
}
}
return [xmin, xmax];
}
contains(lon, lat) {
const [xmin, xmax] = this.getWrappedLongitudes();
let longitudeIn = lon >= xmin && lon <= xmax;
let latitudeIn;
if (this.deltaY >= 0) {
latitudeIn = lat >= this.ymin && lat <= this.ymax;
} else {
latitudeIn = lat >= this.ymax && lat <= this.ymin;
}
return longitudeIn && latitudeIn;
}
getDecimalIndexes(lon, lat) {
const i = floorMod(lon - this.xmin, 360) / this.deltaX;
if (this.flipY) {
const j = (this.ymax - lat) / this.deltaY;
return [i, j];
} else {
const j = (this.ymin + lat) / this.deltaY;
return [i, j];
}
}
valueAt(lon, lat) {
let flag = false;
if (this.wrapX) {
flag = true;
} else if (this.contains(lon, lat)) {
flag = true;
}
if (!flag)
return null;
const indexes = this.getDecimalIndexes(lon, lat);
let ii = Math.floor(indexes[0]);
let jj = Math.floor(indexes[1]);
const ci = this.clampColumnIndex(ii);
const cj = this.clampRowIndex(jj);
return this.valueAtIndexes(ci, cj);
}
interpolatedValueAt(lon, lat) {
let flag = false;
if (this.wrapX) {
flag = true;
} else if (this.contains(lon, lat)) {
flag = true;
}
if (!flag)
return null;
let [i, j] = this.getDecimalIndexes(lon, lat);
return this.interpolatePoint(i, j);
}
hasValueAt(lon, lat) {
let value = this.valueAt(lon, lat);
return value !== null;
}
interpolatePoint(i, j) {
const indexes = this.getFourSurroundingIndexes(i, j);
const [fi, ci, fj, cj] = indexes;
let values = this.getFourSurroundingValues(fi, ci, fj, cj);
if (values) {
const [g00, g10, g01, g11] = values;
return this.bilinearInterpolateVector(i - fi, j - fj, g00, g10, g01, g11);
}
return null;
}
clampColumnIndex(ii) {
let i = ii;
if (ii < 0) {
i = 0;
}
let maxCol = this.cols - 1;
if (ii > maxCol) {
i = maxCol;
}
return i;
}
clampRowIndex(jj) {
let j = jj;
if (jj < 0) {
j = 0;
}
let maxRow = this.rows - 1;
if (jj > maxRow) {
j = maxRow;
}
return j;
}
getFourSurroundingIndexes(i, j) {
let fi = Math.floor(i);
let ci = fi + 1;
if (this.isContinuous && ci >= this.cols) {
ci = 0;
}
ci = this.clampColumnIndex(ci);
let fj = this.clampRowIndex(Math.floor(j));
let cj = this.clampRowIndex(fj + 1);
return [fi, ci, fj, cj];
}
getFourSurroundingValues(fi, ci, fj, cj) {
let row;
if (row = this.grid[fj]) {
const g00 = row[fi];
const g10 = row[ci];
if (this.isValid(g00) && this.isValid(g10) && (row = this.grid[cj])) {
const g01 = row[fi];
const g11 = row[ci];
if (this.isValid(g01) && this.isValid(g11)) {
return [g00, g10, g01, g11];
}
}
}
return null;
}
valueAtIndexes(i, j) {
return this.grid[j][i];
}
lonLatAtIndexes(i, j) {
let lon = this.longitudeAtX(i);
let lat = this.latitudeAtY(j);
return [lon, lat];
}
longitudeAtX(i) {
let halfXPixel = this.deltaX / 2;
let lon = this.xmin + halfXPixel + i * this.deltaX;
if (this.translateX) {
lon = lon > 180 ? lon - 360 : lon;
}
return lon;
}
latitudeAtY(j) {
let halfYPixel = this.deltaY / 2;
return this.ymax - halfYPixel - j * this.deltaY;
}
randomize(o = {}, width, height, unproject) {
let i = Math.random() * (width || this.cols) | 0;
let j = Math.random() * (height || this.rows) | 0;
const coords = unproject([i, j]);
if (coords !== null) {
o.x = coords[0];
o.y = coords[1];
} else {
o.x = this.longitudeAtX(i);
o.y = this.latitudeAtY(j);
}
return o;
}
checkFields() {
return this.isFields;
}
}
const defaultOptions = {
globalAlpha: 0.9,
lineWidth: 1,
colorScale: "#fff",
velocityScale: 1 / 25,
maxAge: 90,
paths: 800,
frameRate: 20,
useCoordsDraw: true,
gpet: true
};
function indexFor(m, min, max, colorScale) {
return Math.max(
0,
Math.min(
colorScale.length - 1,
Math.round((m - min) / (max - min) * (colorScale.length - 1))
)
);
}
class WindCore {
constructor(ctx, options, field) {
this.particles = [];
this.generated = false;
this.ctx = ctx;
if (!this.ctx) {
throw new Error("ctx error");
}
this.animate = this.animate.bind(this);
this.setOptions(options);
if (field) {
this.updateData(field);
}
}
setOptions(options) {
this.options = { ...defaultOptions, ...options };
const { width, height } = this.ctx.canvas;
if ("particleAge" in options && !("maxAge" in options) && isNumber(this.options.particleAge)) {
this.options.maxAge = this.options.particleAge;
}
if ("particleMultiplier" in options && !("paths" in options) && isNumber(this.options.particleMultiplier)) {
this.options.paths = Math.round(
width * height * this.options.particleMultiplier
);
}
this.prerender();
}
getOptions() {
return this.options;
}
updateData(field) {
this.field = field;
if (!this.generated) {
return;
}
this.particles = this.prepareParticlePaths();
}
project(...args) {
throw new Error("project must be overriden");
}
unproject(...args) {
throw new Error("unproject must be overriden");
}
intersectsCoordinate(coordinates) {
throw new Error("must be overriden");
}
clearCanvas() {
this.stop();
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
this.forceStop = false;
}
start() {
this.starting = true;
this.forceStop = false;
this.then = Date.now();
this.animate();
}
stop() {
cancelAnimationFrame(this.animationLoop);
this.starting = false;
this.forceStop = true;
}
animate() {
if (this.animationLoop) {
cancelAnimationFrame(this.animationLoop);
}
this.animationLoop = requestAnimationFrame(this.animate);
const now = Date.now();
const delta = now - this.then;
if (delta > this.options.frameRate) {
this.then = now - delta % this.options.frameRate;
this.render();
}
}
prerender() {
this.generated = false;
if (!this.field) {
return;
}
this.particles = this.prepareParticlePaths();
this.generated = true;
if (!this.starting && !this.forceStop) {
this.starting = true;
this.then = Date.now();
this.animate();
}
}
render() {
this.moveParticles();
this.drawParticles();
this.postrender();
}
postrender() {
}
moveParticles() {
const { width, height } = this.ctx.canvas;
const particles = this.particles;
const maxAge = this.options.maxAge;
const velocityScale = isFunction(this.options.velocityScale) ? this.options.velocityScale() : this.options.velocityScale;
let i = 0;
const len = particles.length;
for (; i < len; i++) {
const particle = particles[i];
if (particle.age > maxAge) {
particle.age = 0;
this.field.randomize(particle, width, height, this.unproject);
}
const x = particle.x;
const y = particle.y;
const vector = this.field.interpolatedValueAt(x, y);
if (vector === null) {
particle.age = maxAge;
} else {
const xt = x + vector.u * velocityScale;
const yt = y + vector.v * velocityScale;
if (this.field.hasValueAt(xt, yt)) {
particle.xt = xt;
particle.yt = yt;
particle.m = vector.m;
} else {
particle.x = xt;
particle.y = yt;
particle.age = maxAge;
}
}
particle.age++;
}
}
fadeIn() {
const prev = this.ctx.globalCompositeOperation;
this.ctx.globalCompositeOperation = "destination-in";
this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
this.ctx.globalCompositeOperation = prev;
}
drawParticles() {
const particles = this.particles;
this.fadeIn();
this.ctx.globalAlpha = this.options.globalAlpha;
this.ctx.fillStyle = `rgba(0, 0, 0, ${this.options.globalAlpha})`;
this.ctx.lineWidth = isNumber(this.options.lineWidth) ? this.options.lineWidth : 1;
this.ctx.strokeStyle = isString(this.options.colorScale) ? this.options.colorScale : "#fff";
let i = 0;
const len = particles.length;
if (this.field && len > 0) {
let min;
let max;
if (isValide(this.options.minVelocity) && isValide(this.options.maxVelocity)) {
min = this.options.minVelocity;
max = this.options.maxVelocity;
} else {
[min, max] = this.field.range;
}
for (; i < len; i++) {
this[this.options.useCoordsDraw ? "drawCoordsParticle" : "drawPixelParticle"](particles[i], min, max);
}
}
}
drawPixelParticle(particle, min, max) {
const pointPrev = [particle.x, particle.y];
const pointNext = [particle.xt, particle.yt];
if (pointNext && pointPrev && isValide(pointNext[0]) && isValide(pointNext[1]) && isValide(pointPrev[0]) && isValide(pointPrev[1]) && particle.age <= this.options.maxAge) {
this.ctx.beginPath();
this.ctx.moveTo(pointPrev[0], pointPrev[1]);
this.ctx.lineTo(pointNext[0], pointNext[1]);
if (isFunction(this.options.colorScale)) {
this.ctx.strokeStyle = this.options.colorScale(particle.m);
} else if (Array.isArray(this.options.colorScale)) {
const colorIdx = indexFor(
particle.m,
min,
max,
this.options.colorScale
);
this.ctx.strokeStyle = this.options.colorScale[colorIdx];
}
if (isFunction(this.options.lineWidth)) {
this.ctx.lineWidth = this.options.lineWidth(particle.m);
}
particle.x = particle.xt;
particle.y = particle.yt;
this.ctx.stroke();
}
}
drawCoordsParticle(particle, min, max) {
const source = [particle.x, particle.y];
const target = [particle.xt, particle.yt];
if (target && source && isValide(target[0]) && isValide(target[1]) && isValide(source[0]) && isValide(source[1]) && this.intersectsCoordinate(target) && particle.age <= this.options.maxAge) {
const pointPrev = this.project(source);
const pointNext = this.project(target);
if (pointPrev && pointNext) {
this.ctx.beginPath();
this.ctx.moveTo(pointPrev[0], pointPrev[1]);
this.ctx.lineTo(pointNext[0], pointNext[1]);
particle.x = particle.xt;
particle.y = particle.yt;
if (isFunction(this.options.colorScale)) {
this.ctx.strokeStyle = this.options.colorScale(particle.m);
} else if (Array.isArray(this.options.colorScale)) {
const colorIdx = indexFor(
particle.m,
min,
max,
this.options.colorScale
);
this.ctx.strokeStyle = this.options.colorScale[colorIdx];
}
if (isFunction(this.options.lineWidth)) {
this.ctx.lineWidth = this.options.lineWidth(particle.m);
}
this.ctx.stroke();
}
}
}
prepareParticlePaths() {
const { width, height } = this.ctx.canvas;
const particleCount = typeof this.options.paths === "function" ? this.options.paths(this) : this.options.paths;
const particles = [];
if (!this.field) {
return [];
}
let i = 0;
for (; i < particleCount; i++) {
particles.push(
this.field.randomize(
{
age: this.randomize()
},
width,
height,
this.unproject
)
);
}
return particles;
}
randomize() {
return Math.floor(Math.random() * this.options.maxAge);
}
}
WindCore.Field = Field;
export { Field, TypeOf, Vector, WindCore, assign, createCanvas, defaultOptions, floorMod, formatData, getColor, isArray, isArrayBuffer, isDate, isEmpty, isFunction, isNull, isNumber, isObject, isString, isValide, removeDomNode, warnLog, warnOnce };
//# sourceMappingURL=wind-core.esm.js.map
wind-gl-core.js
// wind-gl-core.js
var WorkerClass = null;
try {
var WorkerThreads =
typeof module !== 'undefined' && typeof module.require === 'function' && module.require('worker_threads') ||
typeof __non_webpack_require__ === 'function' && __non_webpack_require__('worker_threads') ||
typeof require === 'function' && require('worker_threads');
WorkerClass = WorkerThreads.Worker;
} catch(e) {} // eslint-disable-line
function decodeBase64$1(base64, enableUnicode) {
return Buffer.from(base64, 'base64').toString(enableUnicode ? 'utf16' : 'utf8');
}
function createBase64WorkerFactory$2(base64, sourcemapArg, enableUnicodeArg) {
var sourcemap = sourcemapArg === undefined ? null : sourcemapArg;
var enableUnicode = enableUnicodeArg === undefined ? false : enableUnicodeArg;
var source = decodeBase64$1(base64, enableUnicode);
var start = source.indexOf('\n', 10) + 1;
var body = source.substring(start) + (sourcemap ? '\/\/# sourceMappingURL=' + sourcemap : '');
return function WorkerFactory(options) {
return new WorkerClass(body, Object.assign({}, options, { eval: true }));
};
}
function decodeBase64(base64, enableUnicode) {
var binaryString = atob(base64);
if (enableUnicode) {
var binaryView = new Uint8Array(binaryString.length);
for (var i = 0, n = binaryString.length; i < n; ++i) {
binaryView[i] = binaryString.charCodeAt(i);
}
return String.fromCharCode.apply(null, new Uint16Array(binaryView.buffer));
}
return binaryString;
}
function createURL(base64, sourcemapArg, enableUnicodeArg) {
var sourcemap = sourcemapArg === undefined ? null : sourcemapArg;
var enableUnicode = enableUnicodeArg === undefined ? false : enableUnicodeArg;
var source = decodeBase64(base64, enableUnicode);
var start = source.indexOf('\n', 10) + 1;
var body = source.substring(start) + (sourcemap ? '\/\/# sourceMappingURL=' + sourcemap : '');
var blob = new Blob([body], { type: 'application/javascript' });
return URL.createObjectURL(blob);
}
function createBase64WorkerFactory$1(base64, sourcemapArg, enableUnicodeArg) {
var url;
return function WorkerFactory(options) {
url = url || createURL(base64, sourcemapArg, enableUnicodeArg);
return new Worker(url, options);
};
}
var kIsNodeJS = Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]';
function isNodeJS() {
return kIsNodeJS;
}
function createBase64WorkerFactory(base64, sourcemapArg, enableUnicodeArg) {
if (isNodeJS()) {
return createBase64WorkerFactory$2(base64, sourcemapArg, enableUnicodeArg);
}
return createBase64WorkerFactory$1(base64, sourcemapArg, enableUnicodeArg);
}
var WorkerFactory = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwooZnVuY3Rpb24gKCkgewogICd1c2Ugc3RyaWN0JzsKCiAgZnVuY3Rpb24gY2FsY01pbk1heChhcnJheSkgewogICAgbGV0IG1pbiA9IEluZmluaXR5OwogICAgbGV0IG1heCA9IEluZmluaXR5OwogICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7IGkrKykgewogICAgICBjb25zdCB2YWwgPSBhcnJheVtpXTsKICAgICAgaWYgKG1pbiA9PT0gSW5maW5pdHkpIHsKICAgICAgICBtaW4gPSB2YWw7CiAgICAgIH0gZWxzZSBpZiAobWF4ID09PSBJbmZpbml0eSkgewogICAgICAgIG1heCA9IHZhbDsKICAgICAgICBtaW4gPSBNYXRoLm1pbihtaW4sIG1heCk7CiAgICAgICAgbWF4ID0gTWF0aC5tYXgobWluLCBtYXgpOwogICAgICB9IGVsc2UgewogICAgICAgIG1pbiA9IE1hdGgubWluKHZhbCwgbWluKTsKICAgICAgICBtYXggPSBNYXRoLm1heCh2YWwsIG1heCk7CiAgICAgIH0KICAgIH0KICAgIHJldHVybiBbbWluLCBtYXhdOwogIH0KCiAgY29uc3QgY3R4ID0gc2VsZjsKICBjdHguYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsIGFzeW5jICh7IGRhdGE6IHBheWxvYWQgfSkgPT4gewogICAgY29uc3QgcmVuZGVyRm9ybSA9IHBheWxvYWRbMF07CiAgICBpZiAocmVuZGVyRm9ybSA9PT0gInJnIikgewogICAgICBjb25zdCB1RGF0YSA9IHBheWxvYWRbMV07CiAgICAgIGNvbnN0IHZEYXRhID0gcGF5bG9hZFsyXTsKICAgICAgY29uc3QgW3VNaW4sIHVNYXhdID0gY2FsY01pbk1heCh1RGF0YSk7CiAgICAgIGNvbnN0IFt2TWluLCB2TWF4XSA9IGNhbGNNaW5NYXgodkRhdGEpOwogICAgICBjb25zdCB2ZWxvY2l0eURhdGEgPSBuZXcgVWludDhBcnJheSh1RGF0YS5sZW5ndGggKiA0KTsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB1RGF0YS5sZW5ndGg7IGkrKykgewogICAgICAgIGNvbnN0IHIgPSAyNTUgKiAodURhdGFbaV0gLSB1TWluKSAvICh1TWF4IC0gdU1pbik7CiAgICAgICAgY29uc3QgZyA9IDI1NSAqICh2RGF0YVtpXSAtIHZNaW4pIC8gKHZNYXggLSB2TWluKTsKICAgICAgICB2ZWxvY2l0eURhdGEuc2V0KFtyLCBnLCAwLCAyNTVdLCBpICogNCk7CiAgICAgIH0KICAgICAgY3R4LnBvc3RNZXNzYWdlKFt2ZWxvY2l0eURhdGEuYnVmZmVyLCB1TWluLCB1TWF4LCB2TWluLCB2TWF4XSwgW3ZlbG9jaXR5RGF0YS5idWZmZXJdKTsKICAgIH0gZWxzZSB7CiAgICAgIGNvbnN0IHNpbmdsZURhdGEgPSBwYXlsb2FkWzFdOwogICAgICBjb25zdCBbbWluLCBtYXhdID0gY2FsY01pbk1heChzaW5nbGVEYXRhKTsKICAgICAgY29uc3QgdmVsb2NpdHlEYXRhID0gbmV3IFVpbnQ4QXJyYXkoc2luZ2xlRGF0YS5sZW5ndGggKiA0KTsKICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzaW5nbGVEYXRhLmxlbmd0aDsgaSsrKSB7CiAgICAgICAgY29uc3QgciA9IDI1NSAqIChzaW5nbGVEYXRhW2ldIC0gbWluKSAvIChtYXggLSBtaW4pOwogICAgICAgIHZlbG9jaXR5RGF0YS5zZXQoW3IsIDAsIDAsIDI1NV0sIGkgKiA0KTsKICAgICAgfQogICAgICBjdHgucG9zdE1lc3NhZ2UoW3ZlbG9jaXR5RGF0YS5idWZmZXIsIG1pbiwgbWF4XSwgW3ZlbG9jaXR5RGF0YS5idWZmZXJdKTsKICAgIH0KICB9KTsKCn0pKCk7Ci8vIyBzb3VyY2VNYXBwaW5nVVJMPURhdGFQcm9jZXNzZS5qcy5tYXAKCg==', 'data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGF0YVByb2Nlc3NlLmpzIiwic291cmNlcyI6WyJ3b3JrZXI6Ly93ZWItd29ya2VyL3V0aWxzL2NvbW1vbi50cyIsIndvcmtlcjovL3dlYi13b3JrZXIvd29ya2Vycy9EYXRhUHJvY2Vzc2UudHMiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGZ1bmN0aW9uIGNhbGNNaW5NYXgoYXJyYXk6IG51bWJlcltdKTogW251bWJlciwgbnVtYmVyXSB7XG4gIGxldCBtaW4gPSBJbmZpbml0eTtcbiAgbGV0IG1heCA9IEluZmluaXR5O1xuICAvLyBAZnJvbTogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTM1NDQ0NzYvaG93LXRvLWZpbmQtbWF4LWFuZC1taW4taW4tYXJyYXktdXNpbmctbWluaW11bS1jb21wYXJpc29uc1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGFycmF5Lmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgdmFsID0gYXJyYXlbaV07XG5cbiAgICBpZiAobWluID09PSBJbmZpbml0eSkge1xuICAgICAgbWluID0gdmFsO1xuICAgIH0gZWxzZSBpZiAobWF4ID09PSBJbmZpbml0eSkge1xuICAgICAgbWF4ID0gdmFsO1xuICAgICAgLy8gdXBkYXRlIG1pbiBtYXhcbiAgICAgIC8vIDEuIFBpY2sgMiBlbGVtZW50cyhhLCBiKSwgY29tcGFyZSB0aGVtLiAoc2F5IGEgPiBiKVxuICAgICAgbWluID0gTWF0aC5taW4obWluLCBtYXgpO1xuICAgICAgbWF4ID0gTWF0aC5tYXgobWluLCBtYXgpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyAyLiBVcGRhdGUgbWluIGJ5IGNvbXBhcmluZyAobWluLCBiKVxuICAgICAgLy8gMy4gVXBkYXRlIG1heCBieSBjb21wYXJpbmcgKG1heCwgYSlcbiAgICAgIG1pbiA9IE1hdGgubWluKHZhbCwgbWluKTtcbiAgICAgIG1heCA9IE1hdGgubWF4KHZhbCwgbWF4KTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIFttaW4sIG1heF07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc051bWJlcih2YWw6IGFueSk6IGJvb2xlYW4ge1xuICByZXR1cm4gdHlwZW9mIHZhbCA9PT0gJ251bWJlcicgJiYgIWlzTmFOKHZhbCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1ZhbGlkZSh2YWw6IGFueSk6IGJvb2xlYW4ge1xuICByZXR1cm4gdmFsICE9PSB1bmRlZmluZWQgJiYgdmFsICE9PSBudWxsICYmICFpc05hTih2YWwpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZmluZFN0b3BMZXNzVGhhbk9yRXF1YWxUbyhzdG9wczogbnVtYmVyW10sIGlucHV0OiBudW1iZXIpIHtcbiAgY29uc3QgbGFzdEluZGV4ID0gc3RvcHMubGVuZ3RoIC0gMTtcbiAgbGV0IGxvd2VySW5kZXggPSAwO1xuICBsZXQgdXBwZXJJbmRleCA9IGxhc3RJbmRleDtcbiAgbGV0IGN1cnJlbnRJbmRleCA9IDA7XG4gIGxldCBjdXJyZW50VmFsdWU7XG4gIGxldCBuZXh0VmFsdWU7XG5cbiAgd2hpbGUgKGxvd2VySW5kZXggPD0gdXBwZXJJbmRleCkge1xuICAgIGN1cnJlbnRJbmRleCA9IE1hdGguZmxvb3IoKGxvd2VySW5kZXggKyB1cHBlckluZGV4KSAvIDIpO1xuICAgIGN1cnJlbnRWYWx1ZSA9IHN0b3BzW2N1cnJlbnRJbmRleF07XG4gICAgbmV4dFZhbHVlID0gc3RvcHNbY3VycmVudEluZGV4ICsgMV07XG5cbiAgICBpZiAoY3VycmVudFZhbHVlIDw9IGlucHV0KSB7XG4gICAgICBpZiAoY3VycmVudEluZGV4ID09PSBsYXN0SW5kZXggfHwgaW5wdXQgPCBuZXh0VmFsdWUpIHtcbiAgICAgICAgLy8gU2VhcmNoIGNvbXBsZXRlXG4gICAgICAgIHJldHVybiBjdXJyZW50SW5kZXg7XG4gICAgICB9XG5cbiAgICAgIGxvd2VySW5kZXggPSBjdXJyZW50SW5kZXggKyAxO1xuICAgIH0gZWxzZSBpZiAoY3VycmVudFZhbHVlID4gaW5wdXQpIHtcbiAgICAgIHVwcGVySW5kZXggPSBjdXJyZW50SW5kZXggLSAxO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0lucHV0IGlzIG5vdCBhIG51bWJlci4nKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gMDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGZwNjRMb3dQYXJ0KHg6IG51bWJlcikge1xuICByZXR1cm4geCAtIE1hdGguZnJvdW5kKHgpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbWF0NEludmVydChvdXQ6IG51bWJlcltdLCBhOiBudW1iZXJbXSkge1xuICBjb25zdCBhMDAgPSBhWzBdO1xuICBjb25zdCBhMDEgPSBhWzFdO1xuICBjb25zdCBhMDIgPSBhWzJdO1xuICBjb25zdCBhMDMgPSBhWzNdO1xuICBjb25zdCBhMTAgPSBhWzRdO1xuICBjb25zdCBhMTEgPSBhWzVdO1xuICBjb25zdCBhMTIgPSBhWzZdO1xuICBjb25zdCBhMTMgPSBhWzddO1xuICBjb25zdCBhMjAgPSBhWzhdO1xuICBjb25zdCBhMjEgPSBhWzldO1xuICBjb25zdCBhMjIgPSBhWzEwXTtcbiAgY29uc3QgYTIzID0gYVsxMV07XG4gIGNvbnN0IGEzMCA9IGFbMTJdO1xuICBjb25zdCBhMzEgPSBhWzEzXTtcbiAgY29uc3QgYTMyID0gYVsxNF07XG4gIGNvbnN0IGEzMyA9IGFbMTVdO1xuXG4gIGNvbnN0IGIwMCA9IGEwMCAqIGExMSAtIGEwMSAqIGExMDtcbiAgY29uc3QgYjAxID0gYTAwICogYTEyIC0gYTAyICogYTEwO1xuICBjb25zdCBiMDIgPSBhMDAgKiBhMTMgLSBhMDMgKiBhMTA7XG4gIGNvbnN0IGIwMyA9IGEwMSAqIGExMiAtIGEwMiAqIGExMTtcbiAgY29uc3QgYjA0ID0gYTAxICogYTEzIC0gYTAzICogYTExO1xuICBjb25zdCBiMDUgPSBhMDIgKiBhMTMgLSBhMDMgKiBhMTI7XG4gIGNvbnN0IGIwNiA9IGEyMCAqIGEzMSAtIGEyMSAqIGEzMDtcbiAgY29uc3QgYjA3ID0gYTIwICogYTMyIC0gYTIyICogYTMwO1xuICBjb25zdCBiMDggPSBhMjAgKiBhMzMgLSBhMjMgKiBhMzA7XG4gIGNvbnN0IGIwOSA9IGEyMSAqIGEzMiAtIGEyMiAqIGEzMTtcbiAgY29uc3QgYjEwID0gYTIxICogYTMzIC0gYTIzICogYTMxO1xuICBjb25zdCBiMTEgPSBhMjIgKiBhMzMgLSBhMjMgKiBhMzI7XG5cbiAgLy8gQ2FsY3VsYXRlIHRoZSBkZXRlcm1pbmFudFxuICBsZXQgZGV0ID1cbiAgICBiMDAgKiBiMTEgLSBiMDEgKiBiMTAgKyBiMDIgKiBiMDkgKyBiMDMgKiBiMDggLSBiMDQgKiBiMDcgKyBiMDUgKiBiMDY7XG5cbiAgaWYgKCFkZXQpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBkZXQgPSAxLjAgLyBkZXQ7XG5cbiAgb3V0WzBdID0gKGExMSAqIGIxMSAtIGExMiAqIGIxMCArIGExMyAqIGIwOSkgKiBkZXQ7XG4gIG91dFsxXSA9IChhMDIgKiBiMTAgLSBhMDEgKiBiMTEgLSBhMDMgKiBiMDkpICogZGV0O1xuICBvdXRbMl0gPSAoYTMxICogYjA1IC0gYTMyICogYjA0ICsgYTMzICogYjAzKSAqIGRldDtcbiAgb3V0WzNdID0gKGEyMiAqIGIwNCAtIGEyMSAqIGIwNSAtIGEyMyAqIGIwMykgKiBkZXQ7XG4gIG91dFs0XSA9IChhMTIgKiBiMDggLSBhMTAgKiBiMTEgLSBhMTMgKiBiMDcpICogZGV0O1xuICBvdXRbNV0gPSAoYTAwICogYjExIC0gYTAyICogYjA4ICsgYTAzICogYjA3KSAqIGRldDtcbiAgb3V0WzZdID0gKGEzMiAqIGIwMiAtIGEzMCAqIGIwNSAtIGEzMyAqIGIwMSkgKiBkZXQ7XG4gIG91dFs3XSA9IChhMjAgKiBiMDUgLSBhMjIgKiBiMDIgKyBhMjMgKiBiMDEpICogZGV0O1xuICBvdXRbOF0gPSAoYTEwICogYjEwIC0gYTExICogYjA4ICsgYTEzICogYjA2KSAqIGRldDtcbiAgb3V0WzldID0gKGEwMSAqIGIwOCAtIGEwMCAqIGIxMCAtIGEwMyAqIGIwNikgKiBkZXQ7XG4gIG91dFsxMF0gPSAoYTMwICogYjA0IC0gYTMxICogYjAyICsgYTMzICogYjAwKSAqIGRldDtcbiAgb3V0WzExXSA9IChhMjEgKiBiMDIgLSBhMjAgKiBiMDQgLSBhMjMgKiBiMDApICogZGV0O1xuICBvdXRbMTJdID0gKGExMSAqIGIwNyAtIGExMCAqIGIwOSAtIGExMiAqIGIwNikgKiBkZXQ7XG4gIG91dFsxM10gPSAoYTAwICogYjA5IC0gYTAxICogYjA3ICsgYTAyICogYjA2KSAqIGRldDtcbiAgb3V0WzE0XSA9IChhMzEgKiBiMDEgLSBhMzAgKiBiMDMgLSBhMzIgKiBiMDApICogZGV0O1xuICBvdXRbMTVdID0gKGEyMCAqIGIwMyAtIGEyMSAqIGIwMSArIGEyMiAqIGIwMCkgKiBkZXQ7XG5cbiAgcmV0dXJuIG91dDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zZm9ybU1hdDQob3V0OiBudW1iZXJbXSwgYTogbnVtYmVyW10sIG06IG51bWJlcltdKSB7XG4gIGNvbnN0IHggPSBhWzBdO1xuICBjb25zdCB5ID0gYVsxXTtcbiAgY29uc3QgeiA9IGFbMl07XG4gIGNvbnN0IHcgPSBhWzNdO1xuICBvdXRbMF0gPSBtWzBdICogeCArIG1bNF0gKiB5ICsgbVs4XSAqIHogKyBtWzEyXSAqIHc7IC8vIDBcbiAgb3V0WzFdID0gbVsxXSAqIHggKyBtWzVdICogeSArIG1bOV0gKiB6ICsgbVsxM10gKiB3OyAvLyAwXG4gIG91dFsyXSA9IG1bMl0gKiB4ICsgbVs2XSAqIHkgKyBtWzEwXSAqIHogKyBtWzE0XSAqIHc7IC8vIDBcbiAgb3V0WzNdID0gbVszXSAqIHggKyBtWzddICogeSArIG1bMTFdICogeiArIG1bMTVdICogdzsgLy8gMVxuICByZXR1cm4gb3V0O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0RXllKG1hdHJpeDogbnVtYmVyW10pIHtcbiAgY29uc3QgZGVmYXVsdE1hdDQgPSBbMSwgMCwgMCwgMCwgMCwgMSwgMCwgMCwgMCwgMCwgMSwgMCwgMCwgMCwgMCwgMV07IC8vIGluc3RlZCBvZiBtYXQ0LmNyZWF0ZSgpXG4gIGxldCBleWUgPSB0cmFuc2Zvcm1NYXQ0KFxuICAgIFtdLFxuICAgIFswLCAwLCAwLCAxXSxcbiAgICBtYXQ0SW52ZXJ0KGRlZmF1bHRNYXQ0LCBtYXRyaXgpIGFzIG51bWJlcltdLFxuICApO1xuICBjb25zdCBjbGlwVyA9IDEuMCAvIGV5ZVszXTtcbiAgZXllID0gZXllLm1hcCgoaXRlbTogbnVtYmVyKSA9PiBpdGVtIC8gZXllWzNdKTtcbiAgZXllWzNdID0gY2xpcFc7XG4gIHJldHVybiBleWU7XG59XG4iLCJpbXBvcnQgeyBjYWxjTWluTWF4IH0gZnJvbSAnLi4vdXRpbHMvY29tbW9uJztcblxuY29uc3QgY3R4OiBXb3JrZXIgPSBzZWxmIGFzIGFueTtcblxuY3R4LmFkZEV2ZW50TGlzdGVuZXIoJ21lc3NhZ2UnLCBhc3luYyAoeyBkYXRhOiBwYXlsb2FkIH0pID0+IHtcbiAgY29uc3QgcmVuZGVyRm9ybSA9IHBheWxvYWRbMF07XG4gIGlmIChyZW5kZXJGb3JtID09PSAncmcnKSB7XG4gICAgY29uc3QgdURhdGEgPSBwYXlsb2FkWzFdO1xuICAgIGNvbnN0IHZEYXRhID0gcGF5bG9hZFsyXTtcbiAgICBjb25zdCBbdU1pbiwgdU1heF0gPSBjYWxjTWluTWF4KHVEYXRhKTtcbiAgICBjb25zdCBbdk1pbiwgdk1heF0gPSBjYWxjTWluTWF4KHZEYXRhKTtcbiAgICBjb25zdCB2ZWxvY2l0eURhdGEgPSBuZXcgVWludDhBcnJheSh1RGF0YS5sZW5ndGggKiA0KTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHVEYXRhLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCByID0gMjU1ICogKHVEYXRhW2ldIC0gdU1pbikgLyAodU1heCAtIHVNaW4pO1xuICAgICAgY29uc3QgZyA9IDI1NSAqICh2RGF0YVtpXSAtIHZNaW4pIC8gKHZNYXggLSB2TWluKTtcbiAgICAgIHZlbG9jaXR5RGF0YS5zZXQoW3IsIGcsIDAsIDI1NV0sIGkgKiA0KTtcbiAgICB9XG5cbiAgICBjdHgucG9zdE1lc3NhZ2UoW3ZlbG9jaXR5RGF0YS5idWZmZXIsIHVNaW4sIHVNYXgsIHZNaW4sIHZNYXhdLCBbdmVsb2NpdHlEYXRhLmJ1ZmZlcl0pO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IHNpbmdsZURhdGEgPSBwYXlsb2FkWzFdO1xuICAgIGNvbnN0IFttaW4sIG1heF0gPSBjYWxjTWluTWF4KHNpbmdsZURhdGEpO1xuICAgIGNvbnN0IHZlbG9jaXR5RGF0YSA9IG5ldyBVaW50OEFycmF5KHNpbmdsZURhdGEubGVuZ3RoICogNCk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzaW5nbGVEYXRhLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCByID0gMjU1ICogKHNpbmdsZURhdGFbaV0gLSBtaW4pIC8gKG1heCAtIG1pbik7XG4gICAgICB2ZWxvY2l0eURhdGEuc2V0KFtyLCAwLCAwLCAyNTVdLCBpICogNCk7XG4gICAgfVxuXG4gICAgY3R4LnBvc3RNZXNzYWdlKFt2ZWxvY2l0eURhdGEuYnVmZmVyLCBtaW4sIG1heF0sIFt2ZWxvY2l0eURhdGEuYnVmZmVyXSk7XG4gIH1cbn0pO1xuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztFQUFPLFNBQVMsV0FBVyxLQUFtQyxFQUFBO0VBQzVELEVBQUEsSUFBSSxHQUFNLEdBQUEsUUFBQSxDQUFBO0VBQ1YsRUFBQSxJQUFJLEdBQU0sR0FBQSxRQUFBLENBQUE7RUFFVixFQUFBLEtBQUEsSUFBUyxDQUFJLEdBQUEsQ0FBQSxFQUFHLENBQUksR0FBQSxLQUFBLENBQU0sUUFBUSxDQUFLLEVBQUEsRUFBQTtFQUNyQyxJQUFBLE1BQU0sTUFBTSxLQUFNLENBQUEsQ0FBQSxDQUFBLENBQUE7RUFFbEIsSUFBQSxJQUFJLFFBQVEsUUFBVSxFQUFBO0VBQ3BCLE1BQU0sR0FBQSxHQUFBLEdBQUEsQ0FBQTtFQUFBLEtBQ1IsTUFBQSxJQUFXLFFBQVEsUUFBVSxFQUFBO0VBQzNCLE1BQU0sR0FBQSxHQUFBLEdBQUEsQ0FBQTtFQUdOLE1BQU0sR0FBQSxHQUFBLElBQUEsQ0FBSyxHQUFJLENBQUEsR0FBQSxFQUFLLEdBQUcsQ0FBQSxDQUFBO0VBQ3ZCLE1BQU0sR0FBQSxHQUFBLElBQUEsQ0FBSyxHQUFJLENBQUEsR0FBQSxFQUFLLEdBQUcsQ0FBQSxDQUFBO0VBQUEsS0FDbEIsTUFBQTtFQUdMLE1BQU0sR0FBQSxHQUFBLElBQUEsQ0FBSyxHQUFJLENBQUEsR0FBQSxFQUFLLEdBQUcsQ0FBQSxDQUFBO0VBQ3ZCLE1BQU0sR0FBQSxHQUFBLElBQUEsQ0FBSyxHQUFJLENBQUEsR0FBQSxFQUFLLEdBQUcsQ0FBQSxDQUFBO0VBQUEsS0FDekI7RUFBQSxHQUNGO0VBQ0EsRUFBTyxPQUFBLENBQUMsS0FBSyxHQUFHLENBQUEsQ0FBQTtFQUNsQjs7RUNyQkEsTUFBTSxHQUFjLEdBQUEsSUFBQSxDQUFBO0VBRXBCLEdBQUEsQ0FBSSxpQkFBaUIsU0FBVyxFQUFBLE9BQU8sRUFBRSxJQUFBLEVBQU0sU0FBYyxLQUFBO0VBQzNELEVBQUEsTUFBTSxhQUFhLE9BQVEsQ0FBQSxDQUFBLENBQUEsQ0FBQTtFQUMzQixFQUFBLElBQUksZUFBZSxJQUFNLEVBQUE7RUFDdkIsSUFBQSxNQUFNLFFBQVEsT0FBUSxDQUFBLENBQUEsQ0FBQSxDQUFBO0VBQ3RCLElBQUEsTUFBTSxRQUFRLE9BQVEsQ0FBQSxDQUFBLENBQUEsQ0FBQTtFQUN0QixJQUFBLE1BQU0sQ0FBQyxJQUFBLEVBQU0sSUFBSSxDQUFBLEdBQUksV0FBVyxLQUFLLENBQUEsQ0FBQTtFQUNyQyxJQUFBLE1BQU0sQ0FBQyxJQUFBLEVBQU0sSUFBSSxDQUFBLEdBQUksV0FBVyxLQUFLLENBQUEsQ0FBQTtFQUNyQyxJQUFBLE1BQU0sWUFBZSxHQUFBLElBQUksVUFBVyxDQUFBLEtBQUEsQ0FBTSxTQUFTLENBQUMsQ0FBQSxDQUFBO0VBQ3BELElBQUEsS0FBQSxJQUFTLENBQUksR0FBQSxDQUFBLEVBQUcsQ0FBSSxHQUFBLEtBQUEsQ0FBTSxRQUFRLENBQUssRUFBQSxFQUFBO0VBQ3JDLE1BQUEsTUFBTSxDQUFJLEdBQUEsR0FBQSxJQUFPLEtBQU0sQ0FBQSxDQUFBLENBQUEsR0FBSyxTQUFTLElBQU8sR0FBQSxJQUFBLENBQUEsQ0FBQTtFQUM1QyxNQUFBLE1BQU0sQ0FBSSxHQUFBLEdBQUEsSUFBTyxLQUFNLENBQUEsQ0FBQSxDQUFBLEdBQUssU0FBUyxJQUFPLEdBQUEsSUFBQSxDQUFBLENBQUE7RUFDNUMsTUFBYSxZQUFBLENBQUEsR0FBQSxDQUFJLENBQUMsQ0FBRyxFQUFBLENBQUEsRUFBRyxHQUFHLEdBQUcsQ0FBQSxFQUFHLElBQUksQ0FBQyxDQUFBLENBQUE7RUFBQSxLQUN4QztFQUVBLElBQUEsR0FBQSxDQUFJLFdBQVksQ0FBQSxDQUFDLFlBQWEsQ0FBQSxNQUFBLEVBQVEsSUFBTSxFQUFBLElBQUEsRUFBTSxJQUFNLEVBQUEsSUFBSSxDQUFHLEVBQUEsQ0FBQyxZQUFhLENBQUEsTUFBTSxDQUFDLENBQUEsQ0FBQTtFQUFBLEdBQy9FLE1BQUE7RUFDTCxJQUFBLE1BQU0sYUFBYSxPQUFRLENBQUEsQ0FBQSxDQUFBLENBQUE7RUFDM0IsSUFBQSxNQUFNLENBQUMsR0FBQSxFQUFLLEdBQUcsQ0FBQSxHQUFJLFdBQVcsVUFBVSxDQUFBLENBQUE7RUFDeEMsSUFBQSxNQUFNLFlBQWUsR0FBQSxJQUFJLFVBQVcsQ0FBQSxVQUFBLENBQVcsU0FBUyxDQUFDLENBQUEsQ0FBQTtFQUN6RCxJQUFBLEtBQUEsSUFBUyxDQUFJLEdBQUEsQ0FBQSxFQUFHLENBQUksR0FBQSxVQUFBLENBQVcsUUFBUSxDQUFLLEVBQUEsRUFBQTtFQUMxQyxNQUFBLE1BQU0sQ0FBSSxHQUFBLEdBQUEsSUFBTyxVQUFXLENBQUEsQ0FBQSxDQUFBLEdBQUssUUFBUSxHQUFNLEdBQUEsR0FBQSxDQUFBLENBQUE7RUFDL0MsTUFBYSxZQUFBLENBQUEsR0FBQSxDQUFJLENBQUMsQ0FBRyxFQUFBLENBQUEsRUFBRyxHQUFHLEdBQUcsQ0FBQSxFQUFHLElBQUksQ0FBQyxDQUFBLENBQUE7RUFBQSxLQUN4QztFQUVBLElBQUksR0FBQSxDQUFBLFdBQUEsQ0FBWSxDQUFDLFlBQUEsQ0FBYSxNQUFRLEVBQUEsR0FBQSxFQUFLLEdBQUcsQ0FBRyxFQUFBLENBQUMsWUFBYSxDQUFBLE1BQU0sQ0FBQyxDQUFBLENBQUE7RUFBQSxHQUN4RTtFQUNGLENBQUMsQ0FBQTs7Ozs7OyJ9', false);
/* eslint-enable */
function calcMinMax(array) {
let min = Infinity;
let max = Infinity;
for (let i = 0; i < array.length; i++) {
const val = array[i];
if (min === Infinity) {
min = val;
} else if (max === Infinity) {
max = val;
min = Math.min(min, max);
max = Math.max(min, max);
} else {
min = Math.min(val, min);
max = Math.max(val, max);
}
}
return [min, max];
}
function isNumber(val) {
return typeof val === "number" && !isNaN(val);
}
function isValide(val) {
return val !== void 0 && val !== null && !isNaN(val);
}
function findStopLessThanOrEqualTo(stops, input) {
const lastIndex = stops.length - 1;
let lowerIndex = 0;
let upperIndex = lastIndex;
let currentIndex = 0;
let currentValue;
let nextValue;
while (lowerIndex <= upperIndex) {
currentIndex = Math.floor((lowerIndex + upperIndex) / 2);
currentValue = stops[currentIndex];
nextValue = stops[currentIndex + 1];
if (currentValue <= input) {
if (currentIndex === lastIndex || input < nextValue) {
return currentIndex;
}
lowerIndex = currentIndex + 1;
} else if (currentValue > input) {
upperIndex = currentIndex - 1;
} else {
throw new Error("Input is not a number.");
}
}
return 0;
}
function fp64LowPart(x) {
return x - Math.fround(x);
}
function mat4Invert(out, a) {
const a00 = a[0];
const a01 = a[1];
const a02 = a[2];
const a03 = a[3];
const a10 = a[4];
const a11 = a[5];
const a12 = a[6];
const a13 = a[7];
const a20 = a[8];
const a21 = a[9];
const a22 = a[10];
const a23 = a[11];
const a30 = a[12];
const a31 = a[13];
const a32 = a[14];
const a33 = a[15];
const b00 = a00 * a11 - a01 * a10;
const b01 = a00 * a12 - a02 * a10;
const b02 = a00 * a13 - a03 * a10;
const b03 = a01 * a12 - a02 * a11;
const b04 = a01 * a13 - a03 * a11;
const b05 = a02 * a13 - a03 * a12;
const b06 = a20 * a31 - a21 * a30;
const b07 = a20 * a32 - a22 * a30;
const b08 = a20 * a33 - a23 * a30;
const b09 = a21 * a32 - a22 * a31;
const b10 = a21 * a33 - a23 * a31;
const b11 = a22 * a33 - a23 * a32;
let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (!det) {
return null;
}
det = 1 / det;
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
return out;
}
function transformMat4(out, a, m) {
const x = a[0];
const y = a[1];
const z = a[2];
const w = a[3];
out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
return out;
}
function getEye(matrix) {
const defaultMat4 = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
let eye = transformMat4(
[],
[0, 0, 0, 1],
mat4Invert(defaultMat4, matrix)
);
const clipW = 1 / eye[3];
eye = eye.map((item) => item / eye[3]);
eye[3] = clipW;
return eye;
}
function getDevicePixelRatio() {
return devicePixelRatio || 1;
}
function resizeCanvasSize(canvas, pixelRatio) {
if (!canvas) {
return false;
}
pixelRatio = pixelRatio || getDevicePixelRatio();
if (canvas instanceof HTMLCanvasElement) {
const width = canvas.clientWidth * pixelRatio;
const height = canvas.clientHeight * pixelRatio;
if (width <= 0 || height <= 0) {
return false;
} else if (canvas.width !== width || canvas.height !== height) {
canvas.width = width;
canvas.height = height;
return true;
}
}
return false;
}
function getGlContext(canvas, glOptions = {}) {
const names = ["webgl", "experimental-webgl"];
let context = null;
function onContextCreationError(error) {
console.error(error.statusMessage);
}
canvas.addEventListener(
"webglcontextcreationerror",
onContextCreationError,
false
);
for (let ii = 0; ii < names.length; ++ii) {
try {
context = canvas.getContext(
names[ii],
glOptions
);
} catch (e) {
}
if (context) {
break;
}
}
canvas.removeEventListener(
"webglcontextcreationerror",
onContextCreationError,
false
);
if (!context || !context.getExtension("OES_texture_float")) {
return null;
}
return context;
}
function defineShader(shader, defines) {
return Object.keys(defines).reduce((str, key) => {
return defines[key] ? str + `#define ${key} ${defines[key]}
` : "";
}, "");
}
function injectShaderModule(shader, modules = {}) {
Object.keys(modules).map((key) => {
if (modules[key]) {
shader = shader.replace(new RegExp(key, "g"), `${modules[key]}
`);
}
});
return shader;
}
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
const log = gl.getShaderInfoLog(shader) || "";
gl.deleteShader(shader);
throw new Error(log);
}
return shader;
}
function createProgram(gl, vertexShaderSource, fragmentShaderSource) {
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(
gl,
gl.FRAGMENT_SHADER,
fragmentShaderSource
);
const program = gl.createProgram();
if (program !== null) {
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
throw new Error(gl.getProgramInfoLog(program) || "");
}
}
return program;
}
function createTexture(gl, filter, data, width, height) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
if (data instanceof Uint8Array) {
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
width,
height,
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
data
);
} else {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, data);
}
gl.bindTexture(gl.TEXTURE_2D, null);
return texture;
}
function resizeTexture(gl, texture, width, height, data) {
gl.bindTexture(gl.TEXTURE_2D, texture);
if (data instanceof Uint8Array) {
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
width,
height,
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
data
);
} else {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, data);
}
gl.bindTexture(gl.TEXTURE_2D, null);
}
function bindTexture(gl, texture, unit) {
gl.activeTexture(gl.TEXTURE0 + unit);
gl.bindTexture(gl.TEXTURE_2D, texture);
}
function destroyTexture(gl, texture) {
gl.deleteTexture(texture);
}
function createBuffer(gl, data) {
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
if (data) {
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
}
return buffer;
}
function updateBufferData(gl, buffer, data) {
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
if (data) {
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
}
return buffer;
}
function bindAttribute(gl, buffer, attribute, numComponents) {
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(attribute);
gl.vertexAttribPointer(attribute, numComponents, gl.FLOAT, false, 0, 0);
}
function bindFramebuffer(gl, framebuffer, texture) {
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
if (texture) {
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
texture,
0
);
}
}
function resizeFramebuffer(gl, framebuffer, width, height, texture) {
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
if (texture) {
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
texture,
0
);
}
}
function clearScene(gl, color, depth = 1, stencil = 0, fbo) {
const [r, g, b, a] = color;
let clearFlags = 0;
gl.clearColor(r, g, b, a);
clearFlags |= gl.COLOR_BUFFER_BIT;
if (depth !== void 0) {
gl.clearDepth(depth);
clearFlags |= gl.DEPTH_BUFFER_BIT;
}
if (stencil !== void 0) {
gl.clearStencil(stencil | 0);
clearFlags |= gl.STENCIL_BUFFER_BIT;
}
gl.clear(clearFlags);
}
function loadImage(src) {
return new Promise((resolve, reject) => {
if (!src) {
reject(new Event("url is null"));
}
const image = new Image();
image.crossOrigin = "anonymous";
image.onload = () => resolve(image);
image.onerror = reject;
image.src = src;
if (image.complete) {
resolve(image);
}
});
}
function getPlaneBuffer(startX, endX, startY, endY, widthSegments, heightSegments) {
const width = endX - startX;
const height = endY - startY;
const widthHalf = width / 2;
const heightHalf = height / 2;
const gridX = Math.floor(widthSegments);
const gridY = Math.floor(heightSegments);
const gridX1 = gridX + 1;
const gridY1 = gridY + 1;
const segmentWidth = width / gridX;
const segmentHeight = height / gridY;
const indices = [];
const wireframeIndexes = [];
const vertices = [];
const verticesLow = [];
const uvs = [];
for (let iy = 0; iy < gridY1; iy++) {
const y = iy * segmentHeight;
for (let ix = 0; ix < gridX1; ix++) {
const x = ix * segmentWidth;
const vx = startX + x / widthHalf / 2 * width;
const vy = startY + y / heightHalf / 2 * height;
vertices.push(vx, vy, 0);
verticesLow.push(fp64LowPart(vx), fp64LowPart(vy), 0);
uvs.push(ix / gridX, iy / gridY);
}
}
for (let iy = 0; iy < gridY; iy++) {
for (let ix = 0; ix < gridX; ix++) {
const a = ix + gridX1 * iy;
const b = ix + gridX1 * (iy + 1);
const c = ix + 1 + gridX1 * (iy + 1);
const d = ix + 1 + gridX1 * iy;
indices.push(a, b, d);
indices.push(b, c, d);
}
}
for (let i = 0, l = indices.length; i < l; i += 3) {
const a = indices[i];
const b = indices[i + 1];
const c = indices[i + 2];
wireframeIndexes.push(a, b, b, c, c, a);
}
return {
uvs: {
data: uvs,
size: 2
},
elements: {
data: indices,
count: indices.length
},
wireframeElements: {
data: wireframeIndexes,
count: wireframeIndexes.length
},
position: {
data: vertices,
size: 3
},
positionLow: {
data: verticesLow,
size: 3
}
};
}
class Base {
constructor(gl, vShader, fShader, modules) {
this.vertShader = "";
this.fragShader = "";
if (vShader) {
this.vertShader = vShader;
}
if (fShader) {
this.fragShader = fShader;
}
this.program = createProgram(
gl,
injectShaderModule(this.vertShader, modules),
this.fragShader
);
this.gl = gl;
this.textureUnit = 0;
this.uniformSetters = this.createUniformSetters();
this.attribSetters = this.createAttributeSetters();
this.transfromStack = [];
}
active() {
this.gl.useProgram(this.program);
return this;
}
deactive() {
this.gl.deleteProgram(this.program);
return this;
}
getBindPointForSamplerType(gl, type) {
if (type === gl.SAMPLER_2D) {
return gl.TEXTURE_2D;
}
if (type === gl.SAMPLER_CUBE) {
return gl.TEXTURE_CUBE_MAP;
}
return void 0;
}
createUniformSetter(program, uniformInfo) {
const { gl } = this;
const location = gl.getUniformLocation(program, uniformInfo.name);
const type = uniformInfo.type;
const isArray = uniformInfo.size > 1 && uniformInfo.name.substr(-3) === "[0]";
if (type === gl.FLOAT && isArray) {
return function(v) {
gl.uniform1fv(location, v);
};
}
if (type === gl.FLOAT) {
return function(v) {
gl.uniform1f(location, v);
};
}
if (type === gl.FLOAT_VEC2) {
return function(v) {
gl.uniform2fv(location, v);
};
}
if (type === gl.FLOAT_VEC3) {
return function(v) {
gl.uniform3fv(location, v);
};
}
if (type === gl.FLOAT_VEC4) {
return function(v) {
gl.uniform4fv(location, v);
};
}
if (type === gl.INT && isArray) {
return function(v) {
gl.uniform1iv(location, v);
};
}
if (type === gl.INT) {
return function(v) {
gl.uniform1i(location, v);
};
}
if (type === gl.INT_VEC2) {
return function(v) {
gl.uniform2iv(location, v);
};
}
if (type === gl.INT_VEC3) {
return function(v) {
gl.uniform3iv(location, v);
};
}
if (type === gl.INT_VEC4) {
return function(v) {
gl.uniform4iv(location, v);
};
}
if (type === gl.BOOL) {
return function(v) {
gl.uniform1iv(location, v);
};
}
if (type === gl.BOOL_VEC2) {
return function(v) {
gl.uniform2iv(location, v);
};
}
if (type === gl.BOOL_VEC3) {
return function(v) {
gl.uniform3iv(location, v);
};
}
if (type === gl.BOOL_VEC4) {
return function(v) {
gl.uniform4iv(location, v);
};
}
if (type === gl.FLOAT_MAT2) {
return function(v) {
gl.uniformMatrix2fv(location, false, v);
};
}
if (type === gl.FLOAT_MAT3) {
return function(v) {
gl.uniformMatrix3fv(location, false, v);
};
}
if (type === gl.FLOAT_MAT4) {
return function(v) {
gl.uniformMatrix4fv(location, false, v);
};
}
if ((type === gl.SAMPLER_2D || type === gl.SAMPLER_CUBE) && isArray) {
const units = [];
for (let ii = 0; ii < uniformInfo.size; ++ii) {
units.push(this.textureUnit++);
}
return function(bindPoint, units2) {
return function(textures) {
gl.uniform1iv(location, units2);
textures.forEach(function(texture, index) {
gl.activeTexture(gl.TEXTURE0 + units2[index]);
if (bindPoint !== void 0) {
gl.bindTexture(bindPoint, texture);
}
});
};
}(this.getBindPointForSamplerType(gl, type), units);
}
if (type === gl.SAMPLER_2D || type === gl.SAMPLER_CUBE) {
return function(bindPoint, unit) {
return function(texture) {
gl.uniform1i(location, unit);
gl.activeTexture(gl.TEXTURE0 + unit);
if (bindPoint !== void 0) {
gl.bindTexture(bindPoint, texture);
}
};
}(this.getBindPointForSamplerType(gl, type), this.textureUnit++);
}
throw new Error("unknown type: 0x" + type.toString(16));
}
createUniformSetters() {
const { gl } = this;
this.textureUnit = 0;
const uniformSetters = {};
if (this.program !== null) {
const numUniforms = gl.getProgramParameter(
this.program,
gl.ACTIVE_UNIFORMS
);
for (let ii = 0; ii < numUniforms; ++ii) {
const uniformInfo = gl.getActiveUniform(
this.program,
ii
);
if (!uniformInfo) {
break;
}
let name = uniformInfo.name;
if (name.substr(-3) === "[0]") {
name = name.substr(0, name.length - 3);
}
const setter = this.createUniformSetter(this.program, uniformInfo);
uniformSetters[name] = setter;
}
}
return uniformSetters;
}
createAttribSetter(index) {
const { gl } = this;
return function(b) {
gl.bindBuffer(gl.ARRAY_BUFFER, b.buffer);
gl.enableVertexAttribArray(index);
if (b.numComponents !== void 0 || b.size !== void 0) {
gl.vertexAttribPointer(
index,
b.numComponents || b.size,
b.type || gl.FLOAT,
b.normalize || false,
b.stride || 0,
b.offset || 0
);
}
};
}
createAttributeSetters() {
const { gl } = this;
const attribSetters = {};
if (this.program !== null) {
const numAttribs = gl.getProgramParameter(
this.program,
gl.ACTIVE_ATTRIBUTES
);
for (let ii = 0; ii < numAttribs; ++ii) {
const attribInfo = gl.getActiveAttrib(
this.program,
ii
);
if (!attribInfo) {
break;
}
const index = gl.getAttribLocation(this.program, attribInfo.name);
attribSetters[attribInfo.name] = this.createAttribSetter(index);
}
}
return attribSetters;
}
setAttributes(attribs, setters) {
if (setters) {
setters = setters.attribSetters || setters;
} else {
setters = this.attribSetters;
}
Object.keys(attribs).forEach(function(name) {
const setter = setters[name];
if (setter) {
setter(attribs[name]);
}
});
return this;
}
setUniforms(values, setters) {
if (setters) {
setters = setters.uniformSetters || setters;
} else {
setters = this.uniformSetters;
}
Object.keys(values).forEach(function(name) {
const setter = setters[name];
if (setter) {
setter(values[name]);
}
});
return this;
}
elements(element) {
if (!this.elementsBuffer) {
this.elementsBuffer = this.gl.createBuffer();
}
this.gl.bindBuffer(this.gl.ELEMENT_ARRAY_BUFFER, this.elementsBuffer);
if (element.data) {
this.gl.bufferData(
this.gl.ELEMENT_ARRAY_BUFFER,
element.data,
element.usage || this.gl.STATIC_DRAW
);
}
if (element.count !== void 0) {
this.runTimes(element.count);
}
if (element.primitive) {
this.setPrimitive(element.primitive);
}
return this;
}
clear(color) {
clearScene(this.gl, color);
this.transfromStack = [];
return this;
}
runTimes(count) {
this.count = count || 0;
return this;
}
setPrimitive(primitive) {
this.primitive = primitive || this.gl.TRIANGLES;
return this;
}
resize(width, height) {
if (width === void 0 || height === void 0) {
resizeCanvasSize(this.gl.canvas);
this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
} else {
this.gl.viewport(0, 0, width, height);
}
return this;
}
draw() {
throw new Error("should override");
}
translate() {
throw new Error("should override");
}
rotate() {
throw new Error("should override");
}
scale() {
throw new Error("should override");
}
destroyed() {
throw new Error("should override");
}
}
var FillFrag$1 = "precision highp float;\n#define GLSLIFY 1\nuniform sampler2D u_image;uniform sampler2D u_color_ramp;uniform vec2 u_image_res;uniform vec2 u_range;uniform vec2 u_color_range;uniform vec2 u_display_range;uniform float u_opacity;varying vec2 v_tex_pos;float calcTexture(const vec2 uv){return texture2D(u_image,uv).r;}float bilinear(const vec2 uv){vec2 px=1.0/u_image_res;vec2 vc=(floor(uv*u_image_res))*px;vec2 f=fract(uv*u_image_res);float tl=calcTexture(vc);float tr=calcTexture(vc+vec2(px.x,0));float bl=calcTexture(vc+vec2(0,px.y));float br=calcTexture(vc+px);return mix(mix(tl,tr,f.x),mix(bl,br,f.x),f.y);}float getValue(const vec2 uv){float min=u_range.x;float max=u_range.y;float r=bilinear(uv);return r*(max-min)+min;}const float PI=3.14159265359;vec2 mercatorToWGS84(vec2 xy){float y=radians(180.0-xy.y*360.0);y=360.0/PI*atan(exp(y))-90.0;y=y/-180.0+0.5;return vec2(xy.x,y);}void main(){vec2 globalWGS84=mercatorToWGS84(v_tex_pos);float value=getValue(globalWGS84);float value_t=(value-u_color_range.x)/(u_color_range.y-u_color_range.x);vec2 ramp_pos=vec2(fract(16.0*value_t),floor(16.0*value_t)/16.0);vec4 color=texture2D(u_color_ramp,ramp_pos);bool display=value<u_display_range.y&&value>u_display_range.x;if(display){gl_FragColor=vec4(floor(255.0*color*u_opacity)/255.0);}else{gl_FragColor=vec4(0.0,0.0,0.0,0.0);}}"; // eslint-disable-line
var FillVert$1 = "#define GLSLIFY 1\nattribute vec3 instancePositions;attribute vec3 instancePositions64Low;attribute vec2 a_texCoord;uniform mat4 u_matrix;uniform vec4 u_cameraEye;uniform vec4 u_cameraEye64Low;uniform float u_offset;uniform sampler2D u_image;uniform vec2 u_image_res;uniform vec2 u_range;uniform vec2 u_mapping_range;varying vec2 v_tex_pos;varying float v_value;float calcTexture(const vec2 uv){return texture2D(u_image,uv).r;}float bilinear(const vec2 uv){vec2 px=1.0/u_image_res;vec2 vc=(floor(uv*u_image_res))*px;vec2 f=fract(uv*u_image_res);float tl=calcTexture(vc);float tr=calcTexture(vc+vec2(px.x,0));float bl=calcTexture(vc+vec2(0,px.y));float br=calcTexture(vc+px);return mix(mix(tl,tr,f.x),mix(bl,br,f.x),f.y);}float getValue(const vec2 uv){float min=u_mapping_range.x;float max=u_mapping_range.y;float r=bilinear(uv);return r*(max-min)+min;}const float PI=3.14159265359;vec2 mercatorToWGS84(vec2 xy){float y=radians(180.0-xy.y*360.0);y=360.0/PI*atan(exp(y))-90.0;y=y/-180.0+0.5;return vec2(xy.x,y);}\n#modules-transformZ\nvoid main(){v_tex_pos=a_texCoord;vec2 globalWGS84=mercatorToWGS84(v_tex_pos);float value=getValue(globalWGS84);float z=transformZ(value,instancePositions);vec4 pos=vec4(instancePositions-u_cameraEye.xyz,0.0);pos+=vec4(instancePositions64Low-u_cameraEye64Low.xyz,0.0);\n#modules-project\n}"; // eslint-disable-line
class Fill extends Base {
constructor(gl, vShader, fShader, modules) {
super(gl, vShader || FillVert$1, fShader || FillFrag$1, modules || {});
this.vertShader = FillVert$1;
this.fragShader = FillFrag$1;
}
draw() {
if (this.checkExt !== void 0) {
const primitiveType = this.primitive || this.gl.TRIANGLES;
if (this.checkExt) {
this.gl.drawElements(
primitiveType,
this.count,
this.gl.UNSIGNED_INT,
0
);
} else {
this.gl.drawElements(
primitiveType,
this.count,
this.gl.UNSIGNED_SHORT,
0
);
}
} else {
this.checkExt = this.gl.getExtension("OES_element_index_uint");
}
return this;
}
translate() {
return this;
}
rotate() {
return this;
}
scale() {
return this;
}
}
function parseColorStyle(styleAttrField) {
if (Array.isArray(styleAttrField) && styleAttrField.length > 3) {
const type = styleAttrField[0];
const action = styleAttrField[1];
const interpolateColor = [];
for (let i = 3; i < styleAttrField.length; i += 2) {
const val = styleAttrField[i];
const color = styleAttrField[i + 1];
interpolateColor.push({
key: val,
value: color
});
}
return {
operator: type,
interpolation: {
name: action[0],
base: action[1]
},
input: interpolateColor
};
} else {
console.warn("[wind-core]: style-parser style config invalid");
return {};
}
}
function parseZoomStyle(styleAttrField) {
if (Array.isArray(styleAttrField) && styleAttrField.length > 3) {
const type = styleAttrField[0];
const action = styleAttrField[1];
const interpolateZoom = [];
for (let i = 3; i < styleAttrField.length; i += 2) {
const val = styleAttrField[i];
const color = styleAttrField[i + 1];
interpolateZoom.push({
key: val,
value: color
});
}
return {
operator: type,
interpolation: {
name: action[0],
base: action[1]
},
input: interpolateZoom
};
} else {
console.warn("[wind-core]: style-parser style config invalid");
return {};
}
}
function createLinearGradient(range, styleAttrField) {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = 256;
canvas.height = 1;
const { input: interpolateColor } = parseColorStyle(styleAttrField);
if (ctx && interpolateColor && Array.isArray(interpolateColor)) {
const keys = interpolateColor.map((d) => parseFloat(d.key));
const colorRange = [Math.min(...keys), Math.max(...keys)];
const [min, max] = [range[0] || colorRange[0], range[1] || colorRange[1]];
const gradient = ctx.createLinearGradient(0, 0, 256, 0);
for (let i = 0; i < interpolateColor.length; i += 1) {
const key = interpolateColor[i].key;
const color = interpolateColor[i].value;
gradient.addColorStop((key - min) / (max - min), color);
}
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 256, 1);
return {
data: new Uint8Array(ctx.getImageData(0, 0, 256, 1).data),
colorRange
};
} else {
return {};
}
}
function exponentialInterpolation(input, base, lowerValue, upperValue) {
const difference = upperValue - lowerValue;
const progress = input - lowerValue;
if (difference === 0) {
return 0;
} else if (base === 1) {
return progress / difference;
} else {
return (Math.pow(base, progress) - 1) / (Math.pow(base, difference) - 1);
}
}
function interpolationFactor(interpolation, input, lower, upper) {
let t = 0;
if (interpolation.name === "exponential") {
t = exponentialInterpolation(input, interpolation.base, lower, upper);
} else if (interpolation.name === "linear") {
t = exponentialInterpolation(input, 1, lower, upper);
} else if (interpolation.name === "cubic-bezier") {
console.warn("interpolationFactor");
}
return t;
}
function interpolateNumber(a, b, t) {
return a * (1 - t) + b * t;
}
const cachedStyle = {};
function createZoom(uid, zoom, key, styles, clearCache) {
const ukey = `${uid}_${key}`;
const styleAttrField = styles[key];
if (isNumber(styleAttrField)) {
if (cachedStyle[ukey]) {
delete cachedStyle[ukey];
}
return styleAttrField;
}
if (styleAttrField && Array.isArray(styleAttrField) && (!cachedStyle[ukey] || clearCache)) {
cachedStyle[ukey] = parseZoomStyle(styleAttrField);
}
if (cachedStyle[ukey]) {
const { input: interpolateZoom, interpolation } = cachedStyle[ukey] || {};
if (interpolateZoom && Array.isArray(interpolateZoom)) {
const labels = interpolateZoom.map((i) => i.key);
const outputs = interpolateZoom.map((i) => i.value);
if (zoom <= labels[0]) {
return outputs[0];
}
const stopCount = labels.length;
if (zoom >= labels[stopCount - 1]) {
return outputs[stopCount - 1];
}
const index = findStopLessThanOrEqualTo(labels, zoom);
const idx = labels.length - 1;
const lower = labels[index];
const upper = labels[index >= idx ? idx : index + 1];
const t = interpolationFactor(interpolation, zoom, lower, upper);
const outputLower = outputs[index];
const outputUpper = outputs[index >= idx ? idx : index + 1];
return interpolateNumber(outputLower, outputUpper, t);
} else {
return 1;
}
}
return 1;
}
var FillFrag = "precision highp float;\n#define GLSLIFY 1\nuniform sampler2D u_wind;uniform sampler2D u_color_ramp;uniform vec2 u_image_res;uniform vec2 u_wind_min;uniform vec2 u_wind_max;uniform vec2 u_color_range;uniform vec2 u_display_range;uniform float u_opacity;varying vec2 v_tex_pos;vec2 windTexture(const vec2 uv){return texture2D(u_wind,uv).rg;}float bilinearU(const vec2 uv){vec2 px=1.0/u_image_res;vec2 vc=(floor(uv*u_image_res))*px;vec2 f=fract(uv*u_image_res);float tl=windTexture(vc).r;float tr=windTexture(vc+vec2(px.x,0)).r;float bl=windTexture(vc+vec2(0,px.y)).r;float br=windTexture(vc+px).r;return mix(mix(tl,tr,f.x),mix(bl,br,f.x),f.y);}float bilinearV(const vec2 uv){vec2 px=1.0/u_image_res;vec2 vc=(floor(uv*u_image_res))*px;vec2 f=fract(uv*u_image_res);float tl=windTexture(vc).g;float tr=windTexture(vc+vec2(px.x,0.0)).g;float bl=windTexture(vc+vec2(0.0,px.y)).g;float br=windTexture(vc+px).g;return mix(mix(tl,tr,f.x),mix(bl,br,f.x),f.y);}float getV(const vec2 uv){float min=u_wind_min.y;float max=u_wind_max.y;float r=bilinearV(uv);return r*(max-min)+min;}float getU(const vec2 uv){float min=u_wind_min.x;float max=u_wind_max.x;float r=bilinearU(uv);return r*(max-min)+min;}float windSpeed(const vec2 uv){float u=getU(uv);float v=getV(uv);return length(vec2(u,v));}const float PI=3.14159265359;vec2 mercatorToWGS84(vec2 xy){float y=radians(180.0-xy.y*360.0);y=360.0/PI*atan(exp(y))-90.0;y=y/-180.0+0.5;return vec2(xy.x,y);}void main(){vec2 globalWGS84=mercatorToWGS84(v_tex_pos);float value=windSpeed(globalWGS84);float value_t=(value-u_color_range.x)/(u_color_range.y-u_color_range.x);vec2 ramp_pos=vec2(fract(16.0*value_t),floor(16.0*value_t)/16.0);vec4 color=texture2D(u_color_ramp,ramp_pos);bool display=value<u_display_range.y&&value>u_display_range.x;if(display){gl_FragColor=vec4(floor(255.0*color*u_opacity)/255.0);}else{gl_FragColor=vec4(0.0,0.0,0.0,0.0);}}"; // eslint-disable-line
var FillVert = "#define GLSLIFY 1\nattribute vec3 instancePositions;attribute vec3 instancePositions64Low;attribute vec2 a_texCoord;uniform mat4 u_matrix;uniform vec4 u_cameraEye;uniform vec4 u_cameraEye64Low;uniform float u_offset;uniform sampler2D u_wind;uniform vec2 u_image_res;uniform vec2 u_wind_min;uniform vec2 u_wind_max;uniform vec2 u_mapping_range;varying vec2 v_tex_pos;varying float v_value;vec2 windTexture(const vec2 uv){return texture2D(u_wind,uv).rg;}float bilinearU(const vec2 uv){vec2 px=1.0/u_image_res;vec2 vc=(floor(uv*u_image_res))*px;vec2 f=fract(uv*u_image_res);float tl=windTexture(vc).r;float tr=windTexture(vc+vec2(px.x,0)).r;float bl=windTexture(vc+vec2(0,px.y)).r;float br=windTexture(vc+px).r;return mix(mix(tl,tr,f.x),mix(bl,br,f.x),f.y);}float bilinearV(const vec2 uv){vec2 px=1.0/u_image_res;vec2 vc=(floor(uv*u_image_res))*px;vec2 f=fract(uv*u_image_res);float tl=windTexture(vc).g;float tr=windTexture(vc+vec2(px.x,0.0)).g;float bl=windTexture(vc+vec2(0.0,px.y)).g;float br=windTexture(vc+px).g;return mix(mix(tl,tr,f.x),mix(bl,br,f.x),f.y);}float getV(const vec2 uv){float min=u_wind_min.y;float max=u_wind_max.y;float r=bilinearV(uv);return r*(max-min)+min;}float getU(const vec2 uv){float min=u_wind_min.x;float max=u_wind_max.x;float r=bilinearU(uv);return r*(max-min)+min;}float windSpeed(const vec2 uv){float u=getU(uv);float v=getV(uv);float min=u_mapping_range.x;float max=u_mapping_range.y;float val=length(vec2(u,v));return val*(max-min)+min;}const float PI=3.14159265359;vec2 mercatorToWGS84(vec2 xy){float y=radians(180.0-xy.y*360.0);y=360.0/PI*atan(exp(y))-90.0;y=y/-180.0+0.5;return vec2(xy.x,y);}\n#modules-transformZ\nvoid main(){v_tex_pos=a_texCoord;vec2 globalWGS84=mercatorToWGS84(v_tex_pos);float value=windSpeed(globalWGS84);float z=transformZ(value,instancePositions);vec4 pos=vec4(instancePositions-u_cameraEye.xyz,0.0);pos+=vec4(instancePositions64Low-u_cameraEye64Low.xyz,0.0);\n#modules-project\n}"; // eslint-disable-line
class WindFill extends Base {
constructor(gl, vShader, fShader, modules) {
super(gl, vShader || FillVert, fShader || FillFrag, modules || {});
this.vertShader = FillVert;
this.fragShader = FillFrag;
}
draw() {
if (this.checkExt !== void 0) {
const primitiveType = this.primitive || this.gl.TRIANGLES;
if (this.checkExt) {
this.gl.drawElements(
primitiveType,
this.count,
this.gl.UNSIGNED_INT,
0
);
} else {
this.gl.drawElements(
primitiveType,
this.count,
this.gl.UNSIGNED_SHORT,
0
);
}
} else {
this.checkExt = this.gl.getExtension("OES_element_index_uint");
}
return this;
}
translate() {
return this;
}
rotate() {
return this;
}
scale() {
return this;
}
destroyed() {
}
}
const defaultOptions$2 = {
renderForm: "r",
styleSpec: {
"fill-color": [
"interpolate",
["linear"],
["get", "value"],
0,
"#3288bd",
10,
"#66c2a5",
20,
"#abdda4",
30,
"#e6f598",
40,
"#fee08b",
50,
"#fdae61",
60,
"#f46d43",
100,
"#d53e4f"
],
opacity: 1
},
displayRange: [Infinity, Infinity],
mappingRange: [0, 0],
widthSegments: 1,
heightSegments: 1,
wireframe: false,
createPlaneBuffer: (points, widthSegments, heightSegments) => {
const [startX, endX, startY, endY] = [
points[0][0],
points[2][0],
points[0][1],
points[1][1]
];
return getPlaneBuffer(
startX,
endX,
startY,
endY,
widthSegments,
heightSegments
);
},
injectShaderModules: {
"#modules-transformZ": `
float transformZ(float value, vec3 pos) {
return 0.0;
}
`,
"#modules-project": `
gl_Position = u_matrix * vec4(pos.xy + vec2(u_offset, 0.0), pos.z + z, 1.0);
`
}
};
let uid$1 = 0;
class ScalarFill {
constructor(gl, options) {
this.gl = gl;
this.uid = `ScalarFill_${uid$1}`;
uid$1++;
if (!this.gl) {
throw new Error("initialize error");
}
if (!options) {
options = {};
}
this.options = {
...defaultOptions$2,
...options
};
this.opacity = this.options.opacity || 1;
}
updateOptions(options) {
this.options = {
...this.options,
...options
};
this.buildColorRamp();
if (typeof this.options.getZoom === "function") {
this.setOpacity(
createZoom(
this.uid,
this.options.getZoom(),
"opacity",
this.options.styleSpec,
true
)
);
}
}
setFillColor() {
this.buildColorRamp();
}
setOpacity(opacity) {
this.opacity = opacity;
}
handleZoom() {
if (typeof this.options.getZoom === "function") {
this.setOpacity(
createZoom(
this.uid,
this.options.getZoom(),
"opacity",
this.options.styleSpec
)
);
}
}
buildColorRamp() {
var _a;
const { data, colorRange } = createLinearGradient(
[],
(_a = this.options.styleSpec) == null ? void 0 : _a["fill-color"]
);
if (colorRange) {
this.colorRange = colorRange;
}
if (data) {
this.colorRampTexture = createTexture(
this.gl,
this.gl.NEAREST,
data,
16,
16
);
}
}
initialize(gl) {
if (!this.drawCommand) {
if (this.options.renderForm === "rg") {
this.drawCommand = new WindFill(
gl,
void 0,
void 0,
this.options.injectShaderModules
);
} else if (this.options.renderForm === "r") {
this.drawCommand = new Fill(
gl,
void 0,
void 0,
this.options.injectShaderModules
);
} else {
console.warn("This type is not supported temporarily");
}
}
this.buildColorRamp();
if (typeof this.options.getZoom === "function") {
this.setOpacity(
createZoom(
this.uid,
this.options.getZoom(),
"opacity",
this.options.styleSpec
)
);
}
}
initializeVertex(coordinates) {
let i = 0;
const len = coordinates.length;
const points = [];
for (; i < len; i++) {
const coords = coordinates[i];
const mc = this.getMercatorCoordinate(coords);
points.push([mc[0], mc[1]]);
}
const buffers = (this.options.createPlaneBuffer || defaultOptions$2.createPlaneBuffer)(
points,
this.options.widthSegments || 1,
this.options.heightSegments || 1
);
return {
indexes: buffers.elements.data,
wireframeIndexes: buffers.wireframeElements.data,
quadBuffer: createBuffer(
this.gl,
new Float32Array(buffers.position.data)
),
quad64LowBuffer: createBuffer(
this.gl,
new Float32Array(buffers.positionLow.data)
),
texCoordBuffer: createBuffer(this.gl, new Float32Array(buffers.uvs.data))
};
}
getTextureData(data) {
return new Promise((resolve, reject) => {
if (data.type === "image" && data.url) {
loadImage(data.url).then((image) => {
const processedData = {
width: image.width,
height: image.height,
texture: createTexture(
this.gl,
this.gl.LINEAR,
image,
image.width,
image.height
),
...this.initializeVertex(data.extent)
};
if (this.options.renderForm === "rg") {
processedData.uMin = data.uMin;
processedData.uMax = data.uMax;
processedData.vMin = data.vMin;
processedData.vMax = data.vMax;
} else if (this.options.renderForm === "r") {
processedData.min = data.min;
processedData.max = data.max;
} else {
console.warn("This type is not supported temporarily");
}
resolve(processedData);
}).catch((error) => reject(error));
} else if (data.type === "jsonArray" && data.data) {
const gfsData = data.data;
let pos;
if (data.extent) {
pos = data.extent;
} else {
pos = [
[gfsData[0].header.lo1, gfsData[0].header.la1],
[gfsData[0].header.lo1, gfsData[0].header.la2],
[gfsData[0].header.lo2, gfsData[0].header.la1],
[gfsData[0].header.lo2, gfsData[0].header.la2]
];
}
const processedData = {
width: gfsData[0].header.nx,
height: gfsData[0].header.ny,
...this.initializeVertex(pos)
};
if (!this.worker) {
this.worker = new WorkerFactory();
this.worker.addEventListener("message", ({ data: payload }) => {
if (this.options.renderForm === "rg") {
processedData.uMin = payload[1];
processedData.uMax = payload[2];
processedData.vMin = payload[3];
processedData.vMax = payload[4];
processedData.texture = createTexture(
this.gl,
this.gl.LINEAR,
new Uint8Array(payload[0]),
processedData.width,
processedData.height
);
} else if (this.options.renderForm === "r") {
processedData.min = payload[1];
processedData.max = payload[2];
processedData.texture = createTexture(
this.gl,
this.gl.LINEAR,
new Uint8Array(payload[0]),
processedData.width,
processedData.height
);
} else {
console.warn("This type is not supported temporarily");
}
resolve(processedData);
});
}
if (this.options.renderForm === "rg") {
let uComp;
let vComp;
gfsData.forEach((record) => {
switch (record.header.parameterCategory + "," + record.header.parameterNumber) {
case "1,2":
case "2,2":
uComp = record;
break;
case "1,3":
case "2,3":
vComp = record;
break;
}
});
const u = new Float32Array(uComp.data);
const v = new Float32Array(vComp.data);
this.worker.postMessage(["rg", u, v]);
} else if (this.options.renderForm === "r") {
const singleData = new Float32Array(gfsData[0].data);
this.worker.postMessage(["r", singleData]);
} else {
console.warn("This type is not supported temporarily");
}
}
});
}
setData(data, cb) {
if (this.gl && data) {
this.getTextureData(data).then((d) => {
this.data = d;
cb && cb(true);
if (this.data) {
this.initialize(this.gl);
}
if (this.options.triggerRepaint) {
this.handleZoom();
this.options.triggerRepaint();
}
}).catch((error) => {
cb && cb(false);
console.error(error);
});
}
}
getData() {
return this.data;
}
getMercatorCoordinate([lng, lat]) {
return [lng, lat];
}
prerender() {
}
render(matrix, offsetX, cameraParams) {
if (this.data && this.drawCommand && this.data.texture && this.colorRampTexture) {
const opacity = this.opacity;
const uniforms = {
u_opacity: isNumber(opacity) ? opacity : 1,
u_image_res: [this.data.width, this.data.height],
u_matrix: matrix,
u_offset: isNumber(offsetX) ? offsetX : 0,
u_color_ramp: this.colorRampTexture,
u_color_range: this.colorRange,
u_mapping_range: this.options.mappingRange || [0, 0]
};
if (cameraParams) {
uniforms.u_cameraEye = cameraParams.cameraEye;
uniforms.u_cameraEye64Low = cameraParams.cameraEye64Low;
}
if (this.options.renderForm === "rg") {
uniforms.u_wind_min = [this.data.uMin, this.data.vMin];
uniforms.u_wind_max = [this.data.uMax, this.data.vMax];
uniforms.u_wind = this.data.texture;
const speeds = [
Math.sqrt(
this.data.uMin * this.data.uMin + this.data.vMin * this.data.vMin
),
Math.sqrt(
this.data.uMin * this.data.uMin + this.data.vMax * this.data.vMax
),
Math.sqrt(
this.data.uMax * this.data.uMax + this.data.vMax * this.data.vMax
),
Math.sqrt(
this.data.uMax * this.data.uMax + this.data.vMin * this.data.vMin
)
];
const min = 0;
const max = Math.max(...speeds);
uniforms.u_display_range = this.options.displayRange || [min, max];
} else if (this.options.renderForm === "r") {
uniforms.u_range = [this.data.min, this.data.max];
uniforms.u_image = this.data.texture;
uniforms.u_display_range = this.options.displayRange || [
uniforms.u_range[0] - 1,
uniforms.u_range[1] + 1
];
} else {
console.warn("This type is not supported temporarily");
}
const depthEnabled = this.gl.isEnabled(this.gl.DEPTH_TEST);
this.gl.enable(this.gl.DEPTH_TEST);
this.gl.depthMask(true);
this.gl.depthFunc(this.gl.LEQUAL);
const data = this.options.wireframe ? this.data.wireframeIndexes : this.data.indexes;
this.drawCommand.active().setUniforms(uniforms).setAttributes({
instancePositions: {
buffer: this.data.quadBuffer,
numComponents: 3
},
instancePositions64Low: {
buffer: this.data.quad64LowBuffer,
numComponents: 3
},
a_texCoord: {
buffer: this.data.texCoordBuffer,
numComponents: 2
}
}).elements({
data: new Uint32Array(data),
primitive: this.options.wireframe ? this.gl.LINES : this.gl.TRIANGLES,
count: data == null ? void 0 : data.length,
usage: this.gl.STATIC_DRAW
}).draw();
if (!depthEnabled) {
this.gl.disable(this.gl.DEPTH_TEST);
}
}
}
postrender() {
}
destroyData() {
if (this.data) ;
}
destroyed() {
this.destroyData();
if (this.worker) {
this.worker.terminate();
}
}
}
var drawFrag = "precision highp float;\n#define GLSLIFY 1\nuniform sampler2D u_wind;uniform vec2 u_wind_res;uniform vec4 u_wind_range;uniform vec2 u_color_range;uniform sampler2D u_color_ramp;varying vec2 v_particle_pos;vec2 decodeValue(const vec2 uv){vec4 u_color=texture2D(u_wind,uv);float u=u_wind_range[0]+((u_wind_range[1]-u_wind_range[0])*(u_color.r*255.0-1.0))/254.0;float v=u_wind_range[2]+((u_wind_range[3]-u_wind_range[2])*(u_color.g*255.0-1.0))/254.0;return vec2(u,v);}vec2 lookup_wind(const vec2 uv){vec2 px=1.0/u_wind_res;vec2 vc=(floor(uv*u_wind_res))*px;vec2 f=fract(uv*u_wind_res);vec2 tl=decodeValue(vc);vec2 tr=decodeValue(vc+vec2(px.x,0));vec2 bl=decodeValue(vc+vec2(0,px.y));vec2 br=decodeValue(vc+px);return mix(mix(tl,tr,f.x),mix(bl,br,f.x),f.y);}void main(){vec2 velocity=lookup_wind(v_particle_pos);float speed_t=length(velocity);float value_t=(speed_t-u_color_range.x)/(u_color_range.y-u_color_range.x);vec2 ramp_pos=vec2(fract(16.0*value_t),floor(16.0*value_t)/16.0);vec4 color=texture2D(u_color_ramp,ramp_pos);gl_FragColor=vec4(floor(255.0*color*color.a)/255.0);}"; // eslint-disable-line
var drawVert = "#define GLSLIFY 1\nattribute float a_index;uniform sampler2D u_particles_current;uniform sampler2D u_particles_next;uniform float u_particles_res;uniform vec2 u_world;uniform float u_zoom;uniform vec4 u_bbox;uniform float u_offset;uniform float u_width;uniform float u_aspectRatio;uniform mat4 u_matrix;varying vec2 v_particle_pos;const vec2 bitEnc=vec2(1.0,255.0);const vec2 bitDec=1.0/bitEnc;vec2 fromRGBA(const vec4 color){vec4 rounded_color=floor(color*255.0+0.5)/255.0;float x=dot(rounded_color.rg,bitDec);float y=dot(rounded_color.ba,bitDec);return vec2(x,y);}vec4 buildOffset(vec2 perp){vec2 normal=perp*u_width;normal.x/=u_aspectRatio;return vec4(normal,0.0,0.0);}vec4 buildOffset(vec2 perp,vec2 scale){vec2 normal=perp/scale*u_width;normal.x/=u_aspectRatio;return vec4(normal,0.0,0.0);}vec4 getPosWithProject(vec2 current_pos,vec2 next_pos,float v_index){vec4 currentProjected=u_matrix*vec4(current_pos,0.0,1.0);vec4 nextProjected=u_matrix*vec4(next_pos,0.0,1.0);vec2 currentScreen=currentProjected.xy/currentProjected.w*u_world;vec2 nextScreen=nextProjected.xy/nextProjected.w*u_world;vec2 dir=normalize(nextScreen-currentScreen);vec2 perp=vec2(-dir.y,dir.x);float d=length(nextScreen-currentScreen);vec4 pos=currentProjected;if(a_index-v_index*6.0==0.0){pos=currentProjected+buildOffset(perp);}else if(a_index-v_index*6.0==1.0){pos=currentProjected-buildOffset(perp);}else if(a_index-v_index*6.0==2.0){pos=nextProjected+buildOffset(perp);}else if(a_index-v_index*6.0==3.0){pos=nextProjected+buildOffset(perp);}else if(a_index-v_index*6.0==4.0){pos=nextProjected-buildOffset(perp);}else if(a_index-v_index*6.0==5.0){pos=currentProjected-buildOffset(perp);}if(d>20.0||d<0.01){pos.xy+=u_world*pow(2.0,u_zoom+1.0);}return pos;}void main(){float v_index=floor(a_index/6.0);float ux=fract(v_index/u_particles_res);float vy=floor(v_index/u_particles_res)/u_particles_res;vec4 current_color=texture2D(u_particles_current,vec2(ux,vy));vec4 next_color=texture2D(u_particles_next,vec2(ux,vy));vec2 v_current_particle_pos=fromRGBA(current_color);vec2 v_next_particle_pos=fromRGBA(next_color);vec2 vc_pos=u_bbox.xy+v_current_particle_pos*(u_bbox.zw-u_bbox.xy);vec2 nc_pos=u_bbox.xy+v_next_particle_pos*(u_bbox.zw-u_bbox.xy);v_particle_pos=mix(vc_pos,nc_pos,0.5);v_current_particle_pos=clamp(vc_pos,0.0,1.0)+vec2(u_offset,0.0);v_next_particle_pos=clamp(nc_pos,0.0,1.0)+vec2(u_offset,0.0);gl_PointSize=1.0;gl_Position=getPosWithProject(v_current_particle_pos,v_next_particle_pos,v_index);}"; // eslint-disable-line
var screenFrag = "precision highp float;\n#define GLSLIFY 1\nuniform sampler2D u_screen;uniform float u_opacity;uniform float u_fade;varying vec2 v_tex_pos;void main(){vec4 color=texture2D(u_screen,v_tex_pos);gl_FragColor=vec4(floor(255.0*color*u_opacity*u_fade)/255.0);}"; // eslint-disable-line
var screenVert = "#define GLSLIFY 1\nattribute vec2 a_pos;attribute vec2 a_tex_pos;varying vec2 v_tex_pos;void main(){v_tex_pos=a_tex_pos;gl_Position=vec4(a_pos*2.0-1.0,0,1);}"; // eslint-disable-line
var updateFrag = "precision highp float;\n#define GLSLIFY 1\nuniform sampler2D u_wind;uniform sampler2D u_particles;uniform vec4 u_bbox;uniform vec2 u_wind_res;uniform vec4 u_wind_range;uniform float u_rand_seed;uniform float u_nodata;uniform float u_drop_rate;uniform float u_drop_rate_bump;uniform vec2 u_speed_factor;varying vec2 v_tex_pos;const vec2 bitEnc_0=vec2(1.0,255.0);const vec2 bitDec_0=1.0/bitEnc_0;vec4 toRGBA(const vec2 pos_0){vec2 rg=bitEnc_0*pos_0.x;rg=fract(rg);rg-=rg.yy*vec2(1.0/255.0,0.0);vec2 ba=bitEnc_0*pos_0.y;ba=fract(ba);ba-=ba.yy*vec2(1.0/255.0,0.0);return vec4(rg,ba);}const vec2 bitEnc_1=vec2(1.0,255.0);const vec2 bitDec_1=1.0/bitEnc_1;vec2 fromRGBA(const vec4 color){vec4 rounded_color=floor(color*255.0+0.5)/255.0;float x=dot(rounded_color.rg,bitDec_1);float y=dot(rounded_color.ba,bitDec_1);return vec2(x,y);}const vec3 rand_constants=vec3(12.9898,78.233,4375.85453);float rand(const vec2 co){float t=dot(rand_constants.xy,co);return fract(sin(t)*(rand_constants.z+t));}vec2 decodeValue(const vec2 uv){vec4 u_color=texture2D(u_wind,uv);float u=u_wind_range[0]+((u_wind_range[1]-u_wind_range[0])*(u_color.r*255.0-1.0))/254.0;float v=u_wind_range[2]+((u_wind_range[3]-u_wind_range[2])*(u_color.g*255.0-1.0))/254.0;return vec2(u,v);}vec2 getColor(const vec2 uv){vec2 px=1.0/(u_wind_res);vec2 vc=(floor(uv*(u_wind_res)))*px;vec4 u_color=texture2D(u_wind,vc);return vec2(u_color.r,u_color.g);}vec2 lookup_wind(const vec2 uv){vec2 px=1.0/u_wind_res;vec2 vc=(floor(uv*u_wind_res))*px;vec2 f=fract(uv*u_wind_res);vec2 tl=decodeValue(vc);vec2 tr=decodeValue(vc+vec2(px.x,0));vec2 bl=decodeValue(vc+vec2(0,px.y));vec2 br=decodeValue(vc+px);return mix(mix(tl,tr,f.x),mix(bl,br,f.x),f.y);}void main(){vec4 color=texture2D(u_particles,v_tex_pos);vec2 pos=fromRGBA(color);vec2 global_pos=u_bbox.xy+pos*(u_bbox.zw-u_bbox.xy);vec2 alphas=getColor(global_pos);if(alphas.x<=u_nodata||alphas.y<=u_nodata){discard;}vec2 velocity=lookup_wind(global_pos);float speed_t=length(velocity);vec2 offset=vec2(velocity.x,-velocity.y)*u_speed_factor;pos=fract(1.0+pos+offset);vec2 seed=(pos+v_tex_pos)*u_rand_seed;float drop_rate=u_drop_rate+speed_t*u_drop_rate_bump;float drop=step(1.0-drop_rate,rand(seed));vec2 random_pos=vec2(rand(seed+1.3),rand(seed+2.1));pos=mix(pos,random_pos,drop);gl_FragColor=toRGBA(pos);}"; // eslint-disable-line
var updateVert = "#define GLSLIFY 1\nattribute vec2 a_pos;varying vec2 v_tex_pos;void main(){v_tex_pos=a_pos;gl_Position=vec4(a_pos*2.0-1.0,0,1);}"; // eslint-disable-line
const defaultOptions$1 = {
callback: () => void 0
};
class Raf {
constructor(options = {}) {
this.options = {
...defaultOptions$1,
...options
};
this.reset();
this.animate = this.animate.bind(this);
this.onVisibilityChange = this.onVisibilityChange.bind(this);
}
reset() {
this.animating = false;
this.isVisible = true;
if (this.raf !== void 0) {
cancelAnimationFrame(this.raf);
}
}
start() {
if (this.animating) {
return;
}
this.animating = true;
document.addEventListener(
"visibilitychange",
this.onVisibilityChange,
false
);
this.raf = requestAnimationFrame(this.animate);
}
stop() {
this.reset();
document.removeEventListener(
"visibilitychange",
this.onVisibilityChange,
false
);
}
animate() {
if (!this.animating || !this.isVisible) {
return;
}
this.options.callback((performance || Date).now());
this.raf = requestAnimationFrame(this.animate);
}
onVisibilityChange() {
this.isVisible = !document.hidden;
if (this.isVisible) {
this.reset();
this.start();
}
}
}
const defaultOptions = {
styleSpec: {
color: [
"interpolate",
["linear"],
["get", "value"],
0,
"#fff",
100,
"#fff"
],
opacity: 1,
numParticles: 65535
},
opacity: 1,
lineWidth: 2,
speedFactor: 1,
fadeOpacity: 0.93,
dropRate: 3e-3,
dropRateBump: 2e-3
};
let uid = 0;
class WindParticles {
constructor(gl, options = {}) {
this.gl = gl;
this.uid = `WindParticles_${uid}`;
uid++;
if (!this.gl) {
throw new Error("initialize error");
}
this.options = {
...defaultOptions,
...options
};
this.opacity = this.options.opacity || 1;
this.visible = this.options.visible !== void 0 || true;
this.alpha = 0.9;
this.frameTime = 0;
this.lastTime = 0;
this.initialize(this.gl);
}
initialize(gl) {
this.drawCommand = new Base(gl, drawVert, drawFrag);
this.drawCommand.draw = function() {
this.gl.drawArrays(this.primitive, 0, this.count);
};
this.updateCommand = new Base(gl, updateVert, updateFrag);
this.updateCommand.draw = function() {
this.gl.drawArrays(this.primitive, 0, 4);
};
this.screenCommand = new Base(gl, screenVert, screenFrag);
this.screenCommand.draw = function() {
this.gl.drawArrays(this.primitive, 0, 4);
};
this.fbo = gl.createFramebuffer();
this.raf = new Raf({
callback: () => {
if (this.options.triggerRepaint) {
this.options.triggerRepaint();
}
}
});
this.resize();
this.buildColorRamp();
if (typeof this.options.getZoom === "function") {
const zoom = this.options.getZoom();
this.setOpacity(
createZoom(this.uid, zoom, "opacity", this.options.styleSpec)
);
this.numParticles = createZoom(
this.uid,
zoom,
"numParticles",
this.options.styleSpec
);
}
this.start();
}
set numParticles(numParticles) {
if (numParticles === void 0) {
return;
}
const gl = this.gl;
const particleRes = Math.ceil(Math.sqrt(numParticles));
this.particleStateResolution = particleRes;
this.privateNumParticles = particleRes * particleRes;
const particleState = new Uint8Array(this.privateNumParticles * 4);
for (let i = 0; i < particleState.length; i++) {
particleState[i] = Math.floor(Math.random() * 256);
}
if (!this.currentParticleStateTexture) {
this.currentParticleStateTexture = createTexture(
gl,
gl.NEAREST,
particleState,
particleRes,
particleRes
);
} else {
resizeTexture(
gl,
this.currentParticleStateTexture,
particleRes,
particleRes,
particleState
);
}
if (!this.nextParticleStateTexture) {
this.nextParticleStateTexture = createTexture(
gl,
gl.NEAREST,
particleState,
particleRes,
particleRes
);
} else {
resizeTexture(
gl,
this.nextParticleStateTexture,
particleRes,
particleRes,
particleState
);
}
const num = this.privateNumParticles * 6;
const particleIndices = new Float32Array(num);
for (let i = 0; i < num; i++) {
particleIndices[i] = i;
}
if (!this.particleIndexBuffer) {
this.particleIndexBuffer = createBuffer(gl, particleIndices);
} else {
updateBufferData(gl, this.particleIndexBuffer, particleIndices);
}
}
get numParticles() {
return this.privateNumParticles;
}
updateOptions(options) {
const styleSpec = options.styleSpec || {};
this.options = {
...this.options,
...options,
styleSpec: {
...this.options.styleSpec,
...styleSpec
}
};
this.buildColorRamp();
if (typeof this.options.getZoom === "function") {
const zoom = this.options.getZoom();
this.setOpacity(
createZoom(this.uid, zoom, "opacity", this.options.styleSpec, true)
);
this.numParticles = createZoom(
this.uid,
zoom,
"numParticles",
this.options.styleSpec,
true
);
}
}
setOpacity(opacity) {
this.opacity = opacity;
}
getOpacity() {
return this.opacity;
}
handleMoveend() {
this.updateRenderState();
clearScene(this.gl, [0, 0, 0, 0]);
}
handleMovestart() {
this.alpha = 0;
}
handleZoom() {
if (typeof this.options.getZoom === "function") {
const zoom = this.options.getZoom();
this.setOpacity(
createZoom(this.uid, zoom, "opacity", this.options.styleSpec)
);
this.numParticles = createZoom(
this.uid,
zoom,
"numParticles",
this.options.styleSpec
);
}
}
buildColorRamp() {
var _a;
const { data, colorRange } = createLinearGradient(
[],
(_a = this.options.styleSpec) == null ? void 0 : _a.color
);
if (colorRange) {
this.colorRange = colorRange;
}
if (data) {
this.colorRampTexture = createTexture(
this.gl,
this.gl.NEAREST,
data,
16,
16
);
}
}
drawTexture(matrix) {
if (this.fbo && this.screenTexture && this.nextParticleStateTexture) {
bindFramebuffer(this.gl, this.fbo, this.screenTexture);
const depthEnabled = this.gl.isEnabled(this.gl.DEPTH_TEST);
const blendingEnabled = this.gl.isEnabled(this.gl.BLEND);
this.gl.disable(this.gl.DEPTH_TEST);
this.gl.disable(this.gl.BLEND);
this.screenCommand.active().resize(...this.size).setUniforms({
u_screen: this.backgroundTexture,
u_opacity: this.options.fadeOpacity,
u_fade: 1
}).setAttributes({
a_pos: {
buffer: this.data.backgroundBuffer,
numComponents: 2
},
a_tex_pos: {
buffer: this.data.backgroundTexCoordBuffer,
numComponents: 2
}
}).setPrimitive(this.gl.TRIANGLE_STRIP).draw();
if (depthEnabled) {
this.gl.enable(this.gl.DEPTH_TEST);
}
if (blendingEnabled) {
this.gl.enable(this.gl.BLEND);
}
this.drawParticles(matrix);
bindFramebuffer(this.gl, null);
[this.backgroundTexture, this.screenTexture] = [
this.screenTexture,
this.backgroundTexture
];
}
}
drawScreen() {
const depthEnabled = this.gl.isEnabled(this.gl.DEPTH_TEST);
const blendingEnabled = this.gl.isEnabled(this.gl.BLEND);
this.gl.disable(this.gl.DEPTH_TEST);
this.gl.enable(this.gl.BLEND);
this.gl.blendColor(0, 0, 0, 0);
this.gl.blendFunc(this.gl.ONE, this.gl.ONE_MINUS_SRC_ALPHA);
this.screenCommand.active().resize().setUniforms({
u_screen: this.screenTexture,
u_opacity: this.visible ? this.opacity : 0,
u_fade: this.alpha
}).setAttributes({
a_pos: {
buffer: this.data.buffer,
numComponents: 2
},
a_tex_pos: {
buffer: this.data.texCoordBuffer,
numComponents: 2
}
}).setPrimitive(this.gl.TRIANGLE_STRIP).draw();
if (depthEnabled) {
this.gl.enable(this.gl.DEPTH_TEST);
}
if (!blendingEnabled) {
this.gl.disable(this.gl.BLEND);
}
}
updateParticles() {
if (this.fbo && this.currentParticleStateTexture && this.nextParticleStateTexture) {
bindFramebuffer(this.gl, this.fbo, this.nextParticleStateTexture);
const timeScale = this.options.speedFactor * 2.5;
const depthEnabled = this.gl.isEnabled(this.gl.DEPTH_TEST);
const blendingEnabled = this.gl.isEnabled(this.gl.BLEND);
this.gl.disable(this.gl.DEPTH_TEST);
this.gl.disable(this.gl.BLEND);
this.updateCommand.active().resize(this.particleStateResolution, this.particleStateResolution).setUniforms({
u_wind_res: [this.data.width, this.data.height],
u_rand_seed: Math.random(),
u_wind_range: [
this.data.uMin,
this.data.uMax,
this.data.vMin,
this.data.vMax
],
u_drop_rate: this.options.dropRate,
u_drop_rate_bump: this.options.dropRateBump,
u_speed_factor: [
timeScale * this.frameTime / this.size[0],
timeScale * this.frameTime / this.size[1]
],
u_wind: this.data.texture,
u_bbox: this.renderExtent,
nodata: this.data.nodata,
u_particles: this.currentParticleStateTexture
}).setAttributes({
a_pos: {
buffer: this.data.quadBuffer,
numComponents: 2
}
}).setPrimitive(this.gl.TRIANGLE_STRIP).draw();
if (depthEnabled) {
this.gl.enable(this.gl.DEPTH_TEST);
}
if (blendingEnabled) {
this.gl.enable(this.gl.BLEND);
}
[this.currentParticleStateTexture, this.nextParticleStateTexture] = [
this.nextParticleStateTexture,
this.currentParticleStateTexture
];
}
}
drawParticles(matrix) {
if (this.particleIndexBuffer && this.currentParticleStateTexture && this.nextParticleStateTexture) {
const depthEnabled = this.gl.isEnabled(this.gl.DEPTH_TEST);
const blendingEnabled = this.gl.isEnabled(this.gl.BLEND);
this.gl.disable(this.gl.DEPTH_TEST);
this.gl.disable(this.gl.BLEND);
const zoom = this.options.getZoom();
const worlds = this.options.getWorlds();
for (let i = 0; i < worlds.length; i++) {
this.drawCommand.active().setUniforms({
u_width: this.options.lineWidth,
u_world: this.size,
u_matrix: matrix,
u_zoom: zoom,
u_bbox: this.renderExtent,
u_offset: worlds[i],
u_wind: this.data.texture,
u_wind_res: [this.data.width, this.data.height],
u_wind_range: [
this.data.uMin,
this.data.uMax,
this.data.vMin,
this.data.vMax
],
u_color_ramp: this.colorRampTexture,
u_color_range: this.colorRange,
u_aspectRatio: this.size[0] / this.size[1],
u_particles_current: this.currentParticleStateTexture,
u_particles_next: this.nextParticleStateTexture,
u_particles_res: this.particleStateResolution
}).setAttributes({
a_index: {
buffer: this.particleIndexBuffer,
numComponents: 1
}
}).setPrimitive(this.gl.TRIANGLES).runTimes(this.particleStateResolution ** 2 * 6).draw();
}
if (blendingEnabled) {
this.gl.enable(this.gl.BLEND);
}
if (depthEnabled) {
this.gl.enable(this.gl.DEPTH_TEST);
}
}
}
updateRenderState() {
this.renderExtent = this.options.getExtent();
}
resize() {
const gl = this.gl;
this.size = this.options.getSize();
this.updateRenderState();
const emptyPixels = new Uint8Array(this.size[0] * this.size[1] * 4);
if (!this.backgroundTexture) {
this.backgroundTexture = createTexture(
gl,
gl.NEAREST,
emptyPixels,
this.size[0],
this.size[1]
);
} else {
resizeTexture(
gl,
this.backgroundTexture,
this.size[0],
this.size[1],
emptyPixels
);
}
if (!this.screenTexture) {
this.screenTexture = createTexture(
gl,
gl.NEAREST,
emptyPixels,
this.size[0],
this.size[1]
);
} else {
resizeTexture(
gl,
this.screenTexture,
this.size[0],
this.size[1],
emptyPixels
);
}
if (this.fbo) {
resizeFramebuffer(
gl,
this.fbo,
this.size[0],
this.size[1],
this.screenTexture
);
}
}
start() {
this.raf.start();
if (this.options.triggerRepaint) {
this.options.triggerRepaint();
}
}
stop() {
this.raf.stop();
clearScene(this.gl, [0, 0, 0, 0]);
if (this.options.triggerRepaint) {
this.options.triggerRepaint();
}
}
prerender(matrix) {
if (this.data) {
this.updateParticles();
this.drawTexture(matrix);
const now = 1e-3 * Date.now();
this.frameTime = Math.min(now - (this.lastTime || 0), 0.05);
this.lastTime = now;
}
}
render() {
if (this.data) {
if (this.options.interacting()) {
if (this.alpha < 1) {
this.alpha += 3 * this.frameTime;
if (this.alpha > 1 || !this.frameTime) {
this.alpha = 1;
}
}
}
this.drawScreen();
}
return this;
}
initializeVertex(coordinates) {
let i = 0;
const len = coordinates.length;
const instancePositions = new Float32Array(len * 2);
for (; i < len; i++) {
const coords = coordinates[i];
const mc = this.getMercatorCoordinate(coords);
instancePositions[i * 2] = mc[0];
instancePositions[i * 2 + 1] = mc[1];
}
return {
quadBuffer: createBuffer(
this.gl,
new Float32Array([0, 0, 0, 1, 1, 0, 1, 1])
),
buffer: createBuffer(this.gl, instancePositions),
texCoordBuffer: createBuffer(
this.gl,
new Float32Array([0, 0, 0, 1, 1, 0, 1, 1])
),
backgroundBuffer: createBuffer(
this.gl,
new Float32Array([0, 0, 0, 1, 1, 0, 1, 1])
),
backgroundTexCoordBuffer: createBuffer(
this.gl,
new Float32Array([0, 0, 0, 1, 1, 0, 1, 1])
)
};
}
getTextureData(data) {
return new Promise((resolve, reject) => {
if (data.type === "image" && data.url) {
loadImage(data.url).then((image) => {
const processedData = {
width: image.width,
height: image.height,
texture: createTexture(
this.gl,
this.gl.LINEAR,
image,
image.width,
image.height
),
nodata: data.nodata || 0,
...this.initializeVertex(data.extent)
};
processedData.uMin = data.uMin;
processedData.uMax = data.uMax;
processedData.vMin = data.vMin;
processedData.vMax = data.vMax;
resolve(processedData);
}).catch((error) => reject(error));
}
});
}
setData(data, cb) {
if (this.gl && data) {
this.getTextureData(data).then((d) => {
this.data = d;
cb && cb(true);
if (this.options.triggerRepaint) {
this.options.triggerRepaint();
}
}).catch((error) => {
cb && cb(false);
console.error(error);
});
}
}
getData() {
return this.data;
}
getMercatorCoordinate([lng, lat]) {
return [lng, lat];
}
destroyData() {
if (this.data) {
const {
texture,
quadBuffer,
buffer,
texCoordBuffer,
backgroundBuffer,
backgroundTexCoordBuffer
} = this.data;
if (texture) {
this.gl.deleteTexture(texture);
}
if (buffer) {
this.gl.deleteBuffer(buffer);
}
if (quadBuffer) {
this.gl.deleteBuffer(quadBuffer);
}
if (texCoordBuffer) {
this.gl.deleteBuffer(texCoordBuffer);
}
if (backgroundBuffer) {
this.gl.deleteBuffer(backgroundBuffer);
}
if (backgroundTexCoordBuffer) {
this.gl.deleteBuffer(backgroundTexCoordBuffer);
}
delete this.data;
}
}
destroyed() {
this.stop();
if (this.currentParticleStateTexture) {
this.gl.deleteTexture(this.currentParticleStateTexture);
this.currentParticleStateTexture = null;
}
if (this.nextParticleStateTexture) {
this.gl.deleteTexture(this.nextParticleStateTexture);
this.nextParticleStateTexture = null;
}
if (this.backgroundTexture) {
this.gl.deleteTexture(this.backgroundTexture);
this.backgroundTexture = null;
}
if (this.screenTexture) {
this.gl.deleteTexture(this.screenTexture);
this.screenTexture = null;
}
if (this.fbo) {
this.gl.deleteFramebuffer(this.fbo);
this.fbo = null;
}
this.destroyData();
}
}
export { ScalarFill, WindParticles, bindAttribute, bindFramebuffer, bindTexture, calcMinMax, clearScene, createBuffer, createProgram, createShader, createTexture, defaultOptions$2 as defaultOptions, defineShader, destroyTexture, findStopLessThanOrEqualTo, fp64LowPart, getDevicePixelRatio, getEye, getGlContext, getPlaneBuffer, injectShaderModule, isNumber, isValide, loadImage, mat4Invert, resizeCanvasSize, resizeFramebuffer, resizeTexture, transformMat4, updateBufferData };
//# sourceMappingURL=wind-gl-core.esm.js.map
2. 使用
引入 mapbox-wind 中WindLayer 即可
import { WindLayer } from "./wind/mapbox-wind";
windLayer = new WindLayer("wind", res.data, {
windOptions: {
colorScale: () => {
// // console.log(m);
return "#1280FF";
},
// colorScale: [
// "rgb(36,104, 180)",
// "rgb(60,157, 194)",
// "rgb(128,205,193 )",
// "rgb(151,218,168 )",
// "rgb(198,231,181)",
// "rgb(238,247,217)",
// "rgb(255,238,159)",
// "rgb(252,217,125)",
// "rgb(255,182,100)",
// "rgb(252,150,75)",
// "rgb(250,112,52)",
// "rgb(245,64,32)",
// "rgb(237,45,28)",
// "rgb(220,24,32)",
// "rgb(180,0,35)"
// ],
// velocityScale: 1 / 20,
// paths: 5000,
frameRate: 16,
maxAge: 60,
globalAlpha: 0.95,
velocityScale: 0.01,
// paths: 10000,
paths: 1000,
},
});
图层清除
// 图层清除
// 1. 先调用windLayer自身remove
await windLayer?.remove();
// 2. 再调用地图的removeLayer
if (map.getLayer("wind")) {
await map.removeLayer("wind");
}
添加弹框
通过windLayer.getData().interpolatedValueAt(lng, lat);
const clickFn = (e) => {
const { lng, lat } = e.lngLat;
if (windLayer && windLayer.getData) {
const field = windLayer.getData();
if (field && field.interpolatedValueAt) {
const windValue = field.interpolatedValueAt(lng, lat);
removePopup()
popup = new MaplibreCustom({
map: useInjectMap(),
coordinates: [lng, lat]
})
popup.createCustomPopup({
component: {
component: () => import('./WindPopup.vue'),
props: {
data: {
windValue,
lng,
lat,
direction: getWeatherWindDirection(windValue?.u, windValue?.v),
},
}
}
})
}
}
}