为了方便查找和使用该文件,故放在此处
文件名:cesium-wind.esm.js
/*!
* author: joe <qj5657@gmail.com>
* cesium-wind 1.0.3
* build-time: 2020-9-23 11:17
* LICENSE: MIT
* (c) 2020-2020 https://github.com/QJvic/cesium-wind
*/
import { Cartesian3, SceneTransforms, Cartesian2, Math as Math$1, Ellipsoid, EllipsoidalOccluder } from 'cesium';
/*!
* author: sakitam-fdd <smilefdd@gmail.com>
* wind-core v1.0.0-alpha.9
* build-time: 2020-7-5 23:35
* LICENSE: MIT
* (c) 2017-2020 https://github.com/sakitam-fdd/wind-layer#readme
*/
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
function __spreadArrays() {
var arguments$1 = arguments;
for (var s = 0, i = 0, il = arguments.length; i < il; i++) { s += arguments$1[i].length; }
for (var r = Array(s), k = 0, i = 0; i < il; i++)
{ for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
{ r[k] = a[j]; } }
return r;
}
if (!Array.isArray) {
// @ts-ignore
Array.isArray = function (arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
if (typeof Object.assign != 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) {
var arguments$1 = arguments;
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments$1[index];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}
var hasOwnProperty = Object.prototype.hasOwnProperty;
var symToStringTag = typeof Symbol !== 'undefined' ? Symbol.toStringTag : undefined;
function baseGetTag(value) {
if (value === null) {
return value === undefined ? '[object Undefined]' : '[object Null]';
}
if (!(symToStringTag && symToStringTag in Object(value))) {
return toString.call(value);
}
var isOwn = hasOwnProperty.call(value, symToStringTag);
var tag = value[symToStringTag];
var unmasked = false;
try {
value[symToStringTag] = undefined;
unmasked = true;
}
catch (e) {
}
var result = Object.prototype.toString.call(value);
if (unmasked) {
if (isOwn) {
value[symToStringTag] = tag;
}
else {
delete value[symToStringTag];
}
}
return result;
}
/**
* 判断是否为函数
* @param value
* @returns {boolean}
*/
function isFunction(value) {
if (!isObject(value)) {
return false;
}
var tag = baseGetTag(value);
return tag === '[object Function]' || tag === '[object AsyncFunction]' ||
tag === '[object GeneratorFunction]' || tag === '[object Proxy]';
}
/**
* 判断是否为对象
* @param value
* @returns {boolean}
*/
function isObject(value) {
var type = typeof value;
return value !== null && (type === 'object' || type === 'function');
}
/**
* 判断是否为合法字符串
* @param value
* @returns {boolean}
*/
function isString(value) {
if (value == null) {
return false;
}
return typeof value === 'string' || (value.constructor !== null && value.constructor === String);
}
/**
* 判断是否为数字
* @param value
* @returns {boolean}
*/
function isNumber(value) {
return Object.prototype.toString.call(value) === '[object Number]' && !isNaN(value);
}
/**
* check is array
* @param arr
*/
function isArray(arr) {
return Array.isArray(arr);
}
/**
* assign object
* @param target
* @param sources
*/
function assign(target) {
var arguments$1 = arguments;
var sources = [];
for (var _i = 1; _i < arguments.length; _i++) {
sources[_i - 1] = arguments$1[_i];
}
return Object.assign.apply(Object, __spreadArrays([target], sources));
}
/**
* Get floored division
* @param a
* @param n
* @returns {Number} returns remainder of floored division,
* i.e., floor(a / n). Useful for consistent modulo of negative numbers.
* See http://en.wikipedia.org/wiki/Modulo_operation.
*/
function floorMod(a, n) {
return a - n * Math.floor(a / n);
}
/**
* 检查值是否合法
* @param val
* @returns {boolean}
*/
function isValide(val) {
return val !== undefined && val !== null && !isNaN(val);
}
/**
* format gfs json to vector
* @param data
*/
function formatData(data) {
var uComp;
var vComp;
{
console.time('format-data');
}
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;
}
});
// @ts-ignore
if (!vComp || !uComp)
{ return; }
var header = uComp.header;
var 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
});
{
console.timeEnd('format-data');
}
return vectorField;
}
/**
* 移除 dom
* @param node
* @returns {removeDomNode}
*/
function removeDomNode(node) {
if (!node) {
return null;
}
if (node.parentNode) {
node.parentNode.removeChild(node);
}
return node;
}
// from: https://sourcegraph.com/github.com/IHCantabria/Leaflet.CanvasLayer.Field/-/blob/src/Vector.js?utm_source=share
var Vector = /** @class */ (function () {
function Vector(u, v) {
this.u = u;
this.v = v;
this.m = this.magnitude();
}
/**
* the vector value
* 向量值(流体强度)
* @returns {Number}
*/
Vector.prototype.magnitude = function () {
// Math.pow(u, 2)
// Math.pow(v, 2)
return Math.sqrt(this.u * this.u + this.v * this.v);
};
/**
* Angle in degrees (0 to 360º) --> Towards
* 流体方向
* N is 0º and E is 90º
* @returns {Number}
*/
Vector.prototype.directionTo = function () {
var verticalAngle = Math.atan2(this.u, this.v);
var inDegrees = verticalAngle * (180.0 / Math.PI);
if (inDegrees < 0) {
inDegrees += 360.0;
}
return inDegrees;
};
/**
* Angle in degrees (0 to 360º) From x-->
* N is 0º and E is 90º
* @returns {Number}
*/
Vector.prototype.directionFrom = function () {
var a = this.directionTo();
return (a + 180.0) % 360.0;
};
return Vector;
}());
var Field = /** @class */ (function () {
function Field(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; // x 方向增量
this.deltaY = params.deltaY; // y方向增量
if (this.deltaY < 0 && this.ymin < this.ymax) {
console.warn('[wind-core]: The data is flipY');
}
else {
this.ymin = Math.min(params.ymax, params.ymin);
this.ymax = Math.max(params.ymax, params.ymin);
}
this.isFields = true;
var cols = Math.ceil((this.xmax - this.xmin) / params.deltaX); // 列
var 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');
}
// Math.floor(ni * Δλ) >= 360;
// lon lat 经度 纬度
this.isContinuous = Math.floor(this.cols * params.deltaX) >= 360;
this.wrappedX = 'wrappedX' in params ? params.wrappedX : this.xmax > 180; // [0, 360] --> [-180, 180];
this.grid = this.buildGrid();
this.range = this.calculateRange();
}
// from https://github.com/sakitam-fdd/wind-layer/blob/95368f9433/src/windy/windy.js#L110
Field.prototype.buildGrid = function () {
var grid = [];
var p = 0;
var _a = this, rows = _a.rows, cols = _a.cols, us = _a.us, vs = _a.vs;
for (var j = 0; j < rows; j++) {
var row = [];
for (var i = 0; i < cols; i++, p++) {
var u = us[p];
var v = vs[p];
var 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;
};
Field.prototype.release = function () {
this.grid = [];
};
/**
* grib data extent
* 格点数据范围
*/
Field.prototype.extent = function () {
return [
this.xmin,
this.ymin,
this.xmax,
this.ymax ];
};
/**
* Bilinear interpolation for Vector
* 针对向量进行双线性插值
* https://en.wikipedia.org/wiki/Bilinear_interpolation
* @param {Number} x
* @param {Number} y
* @param {Number[]} g00
* @param {Number[]} g10
* @param {Number[]} g01
* @param {Number[]} g11
* @returns {Vector}
*/
Field.prototype.bilinearInterpolateVector = function (x, y, g00, g10, g01, g11) {
var rx = 1 - x;
var ry = 1 - y;
var a = rx * ry;
var b = x * ry;
var c = rx * y;
var d = x * y;
var u = g00.u * a + g10.u * b + g01.u * c + g11.u * d;
var v = g00.v * a + g10.v * b + g01.v * c + g11.v * d;
return new Vector(u, v);
};
/**
* calculate vector value range
*/
Field.prototype.calculateRange = function () {
if (!this.grid || !this.grid[0])
{ return; }
var rows = this.grid.length;
var cols = this.grid[0].length;
// const vectors = [];
var min;
var max;
// @from: https://stackoverflow.com/questions/13544476/how-to-find-max-and-min-in-array-using-minimum-comparisons
for (var j = 0; j < rows; j++) {
for (var i = 0; i < cols; i++) {
var vec = this.grid[j][i];
if (vec !== null) {
var val = vec.m || vec.magnitude();
// vectors.push();
if (min === undefined) {
min = val;
}
else if (max === undefined) {
max = val;
// update min max
// 1. Pick 2 elements(a, b), compare them. (say a > b)
min = Math.min(min, max);
max = Math.max(min, max);
}
else {
// 2. Update min by comparing (min, b)
// 3. Update max by comparing (max, a)
min = Math.min(val, min);
max = Math.max(val, max);
}
}
}
}
return [min, max];
};
/**
* 检查 uv是否合法
* @param x
* @private
*/
Field.prototype.isValid = function (x) {
return x !== null && x !== undefined;
};
Field.prototype.getWrappedLongitudes = function () {
var xmin = this.xmin;
var xmax = this.xmax;
if (this.wrappedX) {
if (this.isContinuous) {
xmin = -180;
xmax = 180;
}
else {
// not sure about this (just one particular case, but others...?)
xmax = this.xmax - 360;
xmin = this.xmin - 360;
/* eslint-disable no-console */
// console.warn(`are these xmin: ${xmin} & xmax: ${xmax} OK?`);
// TODO: Better throw an exception on no-controlled situations.
/* eslint-enable no-console */
}
}
return [xmin, xmax];
};
Field.prototype.contains = function (lon, lat) {
var _a = this.getWrappedLongitudes(), xmin = _a[0], xmax = _a[1];
var longitudeIn = lon >= xmin && lon <= xmax;
var latitudeIn;
if (this.deltaY >= 0) {
latitudeIn = lat >= this.ymin && lat <= this.ymax;
}
else {
latitudeIn = lat >= this.ymax && lat <= this.ymin;
}
return longitudeIn && latitudeIn;
};
/**
* 获取经纬度所在的位置索引
* @param lon
* @param lat
*/
Field.prototype.getDecimalIndexes = function (lon, lat) {
var i = floorMod(lon - this.xmin, 360) / this.deltaX; // calculate longitude index in wrapped range [0, 360)
var j = (this.ymax - lat) / this.deltaY; // calculate latitude index in direction +90 to -90
return [i, j];
};
/**
* Nearest value at lon-lat coordinates
* 线性插值
* @param lon
* @param lat
*/
Field.prototype.valueAt = function (lon, lat) {
if (!this.contains(lon, lat))
{ return null; }
var indexes = this.getDecimalIndexes(lon, lat);
var ii = Math.floor(indexes[0]);
var jj = Math.floor(indexes[1]);
var ci = this.clampColumnIndex(ii);
var cj = this.clampRowIndex(jj);
return this.valueAtIndexes(ci, cj);
};
/**
* Get interpolated grid value lon-lat coordinates
* 双线性插值
* @param lon
* @param lat
*/
Field.prototype.interpolatedValueAt = function (lon, lat) {
if (!this.contains(lon, lat))
{ return null; }
var _a = this.getDecimalIndexes(lon, lat), i = _a[0], j = _a[1];
return this.interpolatePoint(i, j);
};
Field.prototype.hasValueAt = function (lon, lat) {
var value = this.valueAt(lon, lat);
return value !== null;
};
/**
* 基于向量的双线性插值
* @param i
* @param j
*/
Field.prototype.interpolatePoint = function (i, j) {
// 1 2 After converting λ and φ to fractional grid indexes i and j, we find the
// fi i ci four points 'G' that enclose point (i, j). These points are at the four
// | =1.4 | corners specified by the floor and ceiling of i and j. For example, given
// ---G--|---G--- fj 8 i = 1.4 and j = 8.3, the four surrounding grid points are (1, 8), (2, 8),
// j ___|_ . | (1, 9) and (2, 9).
// =8.3 | |
// ---G------G--- cj 9 Note that for wrapped grids, the first column is duplicated as the last
// | | column, so the index ci can be used without taking a modulo.
var indexes = this.getFourSurroundingIndexes(i, j);
var fi = indexes[0], ci = indexes[1], fj = indexes[2], cj = indexes[3];
var values = this.getFourSurroundingValues(fi, ci, fj, cj);
if (values) {
var g00 = values[0], g10 = values[1], g01 = values[2], g11 = values[3];
// @ts-ignore
return this.bilinearInterpolateVector(i - fi, j - fj, g00, g10, g01, g11);
}
return null;
};
/**
* Check the column index is inside the field,
* adjusting to min or max when needed
* @private
* @param {Number} ii - index
* @returns {Number} i - inside the allowed indexes
*/
Field.prototype.clampColumnIndex = function (ii) {
var i = ii;
if (ii < 0) {
i = 0;
}
var maxCol = this.cols - 1;
if (ii > maxCol) {
i = maxCol;
}
return i;
};
/**
* Check the row index is inside the field,
* adjusting to min or max when needed
* @private
* @param {Number} jj index
* @returns {Number} j - inside the allowed indexes
*/
Field.prototype.clampRowIndex = function (jj) {
var j = jj;
if (jj < 0) {
j = 0;
}
var maxRow = this.rows - 1;
if (jj > maxRow) {
j = maxRow;
}
return j;
};
/**
* from: https://github.com/IHCantabria/Leaflet.CanvasLayer.Field/blob/master/src/Field.js#L252
* 计算索引位置周围的数据
* @private
* @param {Number} i - decimal index
* @param {Number} j - decimal index
* @returns {Array} [fi, ci, fj, cj]
*/
Field.prototype.getFourSurroundingIndexes = function (i, j) {
var fi = Math.floor(i); // 左
var ci = fi + 1; // 右
// duplicate colum to simplify interpolation logic (wrapped value)
if (this.isContinuous && ci >= this.cols) {
ci = 0;
}
ci = this.clampColumnIndex(ci);
var fj = this.clampRowIndex(Math.floor(j)); // 上 纬度方向索引(取整)
var cj = this.clampRowIndex(fj + 1); // 下
return [fi, ci, fj, cj];
};
/**
* from https://github.com/IHCantabria/Leaflet.CanvasLayer.Field/blob/master/src/Field.js#L277
* Get four surrounding values or null if not available,
* from 4 integer indexes
* @private
* @param {Number} fi
* @param {Number} ci
* @param {Number} fj
* @param {Number} cj
* @returns {Array}
*/
Field.prototype.getFourSurroundingValues = function (fi, ci, fj, cj) {
var row;
if ((row = this.grid[fj])) {
var g00 = row[fi]; // << left
var g10 = row[ci]; // right >>
if (this.isValid(g00) &&
this.isValid(g10) &&
(row = this.grid[cj])) {
// lower row vv
var g01 = row[fi]; // << left
var g11 = row[ci]; // right >>
if (this.isValid(g01) && this.isValid(g11)) {
return [g00, g10, g01, g11]; // 4 values found!
}
}
}
return null;
};
/**
* Value for grid indexes
* @param {Number} i - column index (integer)
* @param {Number} j - row index (integer)
* @returns {Vector|Number}
*/
Field.prototype.valueAtIndexes = function (i, j) {
return this.grid[j][i]; // <-- j,i !!
};
/**
* Lon-Lat for grid indexes
* @param {Number} i - column index (integer)
* @param {Number} j - row index (integer)
* @returns {Number[]} [lon, lat]
*/
Field.prototype.lonLatAtIndexes = function (i, j) {
var lon = this.longitudeAtX(i);
var lat = this.latitudeAtY(j);
return [lon, lat];
};
/**
* Longitude for grid-index
* @param {Number} i - column index (integer)
* @returns {Number} longitude at the center of the cell
*/
Field.prototype.longitudeAtX = function (i) {
var halfXPixel = this.deltaX / 2.0;
var lon = this.xmin + halfXPixel + i * this.deltaX;
if (this.wrappedX) {
lon = lon > 180 ? lon - 360 : lon;
}
return lon;
};
/**
* Latitude for grid-index
* @param {Number} j - row index (integer)
* @returns {Number} latitude at the center of the cell
*/
Field.prototype.latitudeAtY = function (j) {
var halfYPixel = this.deltaY / 2.0;
return this.ymax - halfYPixel - j * this.deltaY;
};
/**
* 生成粒子位置
* @param o
* @param width
* @param height
* @param unproject
*/
Field.prototype.randomize = function (o, width, height, unproject) {
if (o === void 0) { o = {}; }
var i = (Math.random() * (width || this.cols)) | 0;
var j = (Math.random() * (height || this.rows)) | 0;
var 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;
};
/**
* check is custom field
*/
Field.prototype.checkFields = function () {
return this.isFields;
};
Field.prototype.startBatchInterpolate = function (width, height, unproject) { };
return Field;
}());
var defaultOptions = {
globalAlpha: 0.9,
lineWidth: 1,
colorScale: '#fff',
velocityScale: 1 / 25,
// particleAge: 90, // 粒子在重新生成之前绘制的最大帧数
maxAge: 90,
// particleMultiplier: 1 / 300, // TODO: PATHS = Math.round(width * height * particleMultiplier);
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))));
}
var BaseLayer = /** @class */ (function () {
function BaseLayer(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);
}
}
BaseLayer.prototype.setOptions = function (options) {
this.options = Object.assign({}, defaultOptions, options);
var _a = this.ctx.canvas, width = _a.width, height = _a.height;
if (('particleAge' in options) && !('maxAge' in options) && isNumber(this.options.particleAge)) {
// @ts-ignore
this.options.maxAge = this.options.particleAge;
}
if (('particleMultiplier' in options) && !('paths' in options) && isNumber(this.options.particleMultiplier)) {
// @ts-ignore
this.options.paths = Math.round(width * height * this.options.particleMultiplier);
}
this.prerender();
};
BaseLayer.prototype.getOptions = function () {
return this.options;
};
BaseLayer.prototype.updateData = function (field) {
this.field = field;
if (!this.generated)
{ return; }
this.particles = this.prepareParticlePaths();
};
BaseLayer.prototype.moveParticles = function () {
var _a = this.ctx.canvas, width = _a.width, height = _a.height;
var particles = this.particles;
// 清空组
var maxAge = this.options.maxAge;
var optVelocityScale = isFunction(this.options.velocityScale)
// @ts-ignore
? this.options.velocityScale()
: this.options.velocityScale;
var velocityScale = optVelocityScale;
var i = 0;
var len = particles.length;
for (; i < len; i++) {
var particle = particles[i];
if (particle.age > maxAge) {
particle.age = 0;
// restart, on a random x,y
this.field.randomize(particle, width, height, this.unproject);
}
var x = particle.x;
var y = particle.y;
var vector = this.field.interpolatedValueAt(x, y);
if (vector === null) {
particle.age = maxAge;
}
else {
var xt = x + vector.u * velocityScale;
var yt = y + vector.v * velocityScale;
if (this.field.hasValueAt(xt, yt)) {
// Path from (x,y) to (xt,yt) is visible, so add this particle to the appropriate draw bucket.
particle.xt = xt;
particle.yt = yt;
particle.m = vector.m;
}
else {
// Particle isn't visible, but it still moves through the field.
particle.x = xt;
particle.y = yt;
particle.age = maxAge;
}
}
particle.age++;
}
};
BaseLayer.prototype.fadeIn = function () {
var prev = this.ctx.globalCompositeOperation; // lighter
this.ctx.globalCompositeOperation = 'destination-in';
this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
this.ctx.globalCompositeOperation = prev;
};
BaseLayer.prototype.drawParticles = function () {
var _a;
var 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');
var i = 0;
var len = particles.length;
if (this.field && len > 0) {
var min = void 0;
var max = void 0;
// 如果配置了风速范围
if (isValide(this.options.minVelocity) && isValide(this.options.maxVelocity)) {
min = this.options.minVelocity;
max = this.options.maxVelocity;
}
else { // 未配置风速范围取格点数据中的最大风速和最小风速
_a = this.field.range, min = _a[0], max = _a[1];
}
for (; i < len; i++) {
this[this.options.useCoordsDraw ? 'drawCoordsParticle' : 'drawPixelParticle'](particles[i], min, max);
}
}
};
/**
* 用于绘制像素粒子
* @param particle
* @param min
* @param max
*/
BaseLayer.prototype.drawPixelParticle = function (particle, min, max) {
// TODO 需要判断粒子是否超出视野
// this.ctx.strokeStyle = color;
var pointPrev = [particle.x, particle.y];
// when xt isn't exit
var 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)) {
// @ts-ignore
this.ctx.strokeStyle = this.options.colorScale(particle.m);
}
else if (Array.isArray(this.options.colorScale)) {
var colorIdx = indexFor(particle.m, min, max, this.options.colorScale);
this.ctx.strokeStyle = this.options.colorScale[colorIdx];
}
if (isFunction(this.options.lineWidth)) {
// @ts-ignore
this.ctx.lineWidth = this.options.lineWidth(particle.m);
}
particle.x = particle.xt;
particle.y = particle.yt;
this.ctx.stroke();
}
};
/**
* 用于绘制坐标粒子
* @param particle
* @param min
* @param max
*/
BaseLayer.prototype.drawCoordsParticle = function (particle, min, max) {
// TODO 需要判断粒子是否超出视野
// this.ctx.strokeStyle = color;
var source = [particle.x, particle.y];
// when xt isn't exit
var 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) {
var pointPrev = this.project(source);
var 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)) {
// @ts-ignore
this.ctx.strokeStyle = this.options.colorScale(particle.m);
}
else if (Array.isArray(this.options.colorScale)) {
var colorIdx = indexFor(particle.m, min, max, this.options.colorScale);
this.ctx.strokeStyle = this.options.colorScale[colorIdx];
}
if (isFunction(this.options.lineWidth)) {
// @ts-ignore
this.ctx.lineWidth = this.options.lineWidth(particle.m);
}
this.ctx.stroke();
}
}
};
BaseLayer.prototype.prepareParticlePaths = function () {
var _a = this.ctx.canvas, width = _a.width, height = _a.height;
var particleCount = typeof this.options.paths === 'function' ? this.options.paths(this) : this.options.paths;
var particles = [];
if (!this.field)
{ return []; }
if ('startBatchInterpolate' in this.field) {
this.field.startBatchInterpolate(width, height, this.unproject);
}
var i = 0;
for (; i < particleCount; i++) {
particles.push(this.field.randomize({
age: this.randomize()
}, width, height, this.unproject));
}
return particles;
};
BaseLayer.prototype.randomize = function () {
return Math.floor(Math.random() * this.options.maxAge); // 例如最大生成90帧插值粒子路径
};
// @ts-ignore
BaseLayer.prototype.project = function () {
var arguments$1 = arguments;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments$1[_i];
}
throw new Error('project must be overriden');
};
// @ts-ignore
BaseLayer.prototype.unproject = function () {
var arguments$1 = arguments;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments$1[_i];
}
throw new Error('unproject must be overriden');
};
BaseLayer.prototype.intersectsCoordinate = function (coordinates) {
throw new Error('must be overriden');
};
BaseLayer.prototype.clearCanvas = function () {
this.stop();
this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
this.forceStop = false;
};
BaseLayer.prototype.start = function () {
this.starting = true;
this.forceStop = false;
this._then = Date.now();
this.animate();
};
BaseLayer.prototype.stop = function () {
cancelAnimationFrame(this.animationLoop);
this.starting = false;
this.forceStop = true;
};
BaseLayer.prototype.animate = function () {
if (this.animationLoop)
{ cancelAnimationFrame(this.animationLoop); }
this.animationLoop = requestAnimationFrame(this.animate);
var now = Date.now();
var delta = now - this._then;
if (delta > this.options.frameRate) {
this._then = now - (delta % this.options.frameRate);
this.render();
}
};
/**
* 渲染前处理
*/
BaseLayer.prototype.prerender = function () {
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();
}
};
/**
* 开始渲染
*/
BaseLayer.prototype.render = function () {
this.moveParticles();
this.drawParticles();
this.postrender();
};
/**
* each frame render end
*/
BaseLayer.prototype.postrender = function () { };
BaseLayer.Field = Field;
return BaseLayer;
}());
class CesiumWind {
constructor(data, options = {}) {
this.canvas = null;
this.wind = null;
this.field = null;
this.viewer = null;
this.options = assign({}, options);
this.pickWindOptions();
const canvas = document.createElement('canvas');
canvas.style.cssText =
'position:absolute; left:0; top:0;user-select:none;pointer-events: none;';
canvas.className = 'cesium-wind-j';
this.canvas = canvas;
if (data) {
this.setData(data);
}
}
addTo(viewer) {
this.viewer = viewer;
this.appendCanvas();
this.render(this.canvas);
}
remove() {
if (!this.viewer) {
return;
}
if (this.wind) {
this.wind.stop();
}
if (this.canvas) {
removeDomNode(this.canvas);
}
delete this.canvas;
}
removeLayer() {
this.remove();
}
setData(data) {
if (data && data.checkFields && data.checkFields()) {
this.field = data;
} else if (isArray(data)) {
this.field = formatData(data);
} else {
console.error('Illegal data');
}
if (this.viewer && this.canvas && this.field) {
this.wind.updateData(this.field);
this.appendCanvas();
this.render(this.canvas);
}
return this;
}
getData() {
return this.field;
}
getWindOptions() {
return this.options.windOptions || {};
}
pickWindOptions() {
Object.keys(defaultOptions).forEach((key) => {
if (key in this.options) {
if (this.options.windOptions === undefined) {
this.options.windOptions = {};
}
this.options.windOptions[key] = this.options[key];
}
});
}
getContext() {
if (this.canvas === null) {
return;
}
return this.canvas.getContext('2d');
}
appendCanvas() {
if (!this.viewer || !this.canvas) {
return;
}
if (document.querySelector('.cesium-wind-j')) {
return;
}
this.adjustSize();
const cesiumWidget = this.viewer.canvas.parentNode;
cesiumWidget.appendChild(this.canvas);
}
adjustSize() {
const viewer = this.viewer;
const canvas = this.canvas;
const {width, height} = viewer.canvas;
const devicePixelRatio = 1;
canvas.width = width * devicePixelRatio;
canvas.height = height * devicePixelRatio;
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
}
render(canvas) {
if (!this.getData() || !this.viewer) {
return this;
}
const opt = this.getWindOptions();
if (canvas && !this.wind) {
const data = this.getData();
const ctx = this.getContext();
if (ctx) {
this.wind = new BaseLayer(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 = () => {
};
}
}
if (this.wind) {
this.wind.prerender();
this.wind.render();
}
return this;
}
project(coordinate) {
const position = Cartesian3.fromDegrees(
coordinate[0],
coordinate[1],
);
const scene = this.viewer.scene;
const sceneCoor = SceneTransforms.wgs84ToWindowCoordinates(
scene,
position,
);
return [sceneCoor.x, sceneCoor.y];
}
unproject(pixel) {
const viewer = this.viewer;
const pick = new Cartesian2(pixel[0], pixel[1]);
const cartesian = viewer.scene.globe.pick(
viewer.camera.getPickRay(pick),
viewer.scene,
);
if (!cartesian) {
return null;
}
const ellipsoid = viewer.scene.globe.ellipsoid;
const cartographic = ellipsoid.cartesianToCartographic(cartesian);
const lat = Math$1.toDegrees(cartographic.latitude);
const lng = Math$1.toDegrees(cartographic.longitude);
return [lng, lat];
}
intersectsCoordinate(coordinate) {
const ellipsoid = Ellipsoid.WGS84;
const camera = this.viewer.camera;
const occluder = new EllipsoidalOccluder(ellipsoid, camera.position);
const point = Cartesian3.fromDegrees(coordinate[0], coordinate[1]);
return occluder.isPointVisible(point);
}
}
const WindLayer = CesiumWind;
export default CesiumWind;
export { Field, WindLayer };
//# sourceMappingURL=cesium-wind.esm.js.map