{"version":3,"sources":["jsdelivr-header.js","/npm/core/src/utils.ts","/npm/core/src/Vector.ts","/npm/core/src/Field.ts","/npm/core/src/index.ts","/npm/ol5-wind@1.1.7/src/index.ts"],"names":[],"mappings":"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","file":"/npm/ol5-wind@1.1.7/dist/ol-wind.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/ol5-wind@1.1.7/dist/ol-wind.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","import Field from './Field';\nimport type { IField } from './Field';\n\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\nconst symToStringTag = typeof Symbol !== 'undefined' ? Symbol.toStringTag : undefined;\n\nfunction baseGetTag(value: any) {\n  if (value === null) {\n    return value === undefined ? '[object Undefined]' : '[object Null]';\n  }\n  if (!(symToStringTag && symToStringTag in Object(value))) {\n    return toString.call(value);\n  }\n  const isOwn = hasOwnProperty.call(value, symToStringTag);\n  const tag = value[symToStringTag];\n  let unmasked = false;\n  try {\n    value[symToStringTag] = undefined;\n    unmasked = true;\n  } catch (e) {\n    //\n  }\n\n  const result = Object.prototype.toString.call(value);\n  if (unmasked) {\n    if (isOwn) {\n      value[symToStringTag] = tag;\n    } else {\n      delete value[symToStringTag];\n    }\n  }\n  return result;\n}\n\nexport function TypeOf(value: any) {\n  return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();\n}\n\n/**\n * 判断是否为函数\n * @param value\n * @returns {boolean}\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n  // eslint-disable-next-line @typescript-eslint/no-use-before-define\n  if (!isObject(value)) {\n    return false;\n  }\n  const tag = baseGetTag(value);\n  return (\n    tag === '[object Function]' ||\n    tag === '[object AsyncFunction]' ||\n    tag === '[object GeneratorFunction]' ||\n    tag === '[object Proxy]'\n  );\n}\n\n/**\n * 判断是否为对象\n * @param value\n * @returns {boolean}\n */\nexport function isObject(value: any) {\n  const type = typeof value;\n  return value !== null && (type === 'object' || type === 'function');\n}\n\n/**\n * is date value\n * @param val\n * @returns {boolean}\n */\nexport function isDate(val: any) {\n  return Object.prototype.toString.call(val) === '[object Date]';\n}\n\n/**\n * is array buffer\n * @param val\n * @returns {boolean}\n */\nexport function isArrayBuffer(val: any) {\n  return Object.prototype.toString.call(val) === '[object ArrayBuffer]';\n}\n\n/**\n * 判断是否为合法字符串\n * @param value\n * @returns {boolean}\n */\nexport function isString(value: any): boolean {\n  if (value == null) {\n    return false;\n  }\n  return typeof value === 'string' || (value.constructor !== null && value.constructor === String);\n}\n\n/**\n * 判断是否为数字\n * @param value\n * @returns {boolean}\n */\nexport function isNumber(value: any) {\n  return Object.prototype.toString.call(value) === '[object Number]' && !isNaN(value);\n}\n\n/**\n * 判断对象是否为空\n * @param object\n * @returns {boolean}\n */\nexport function isEmpty(object: any) {\n  let property;\n  for (property in object) {\n    return false;\n  }\n  return !property;\n}\n\n/**\n * 判断是否为 `null`\n * @param obj\n * @returns {boolean}\n */\nexport function isNull(obj: any) {\n  return obj == null;\n}\n\n/**\n * 判断是否是数组\n * @param arr\n */\nexport function isArray(arr: any): boolean {\n  return Array.isArray(arr);\n}\n\n/**\n * assign object\n * @param target\n * @param sources\n */\nexport function assign(target: object, ...sources: any[]) {\n  return Object.assign(target, ...sources);\n}\n\n/**\n * 打印⚠️信息\n * @param msg\n * @param n\n */\nexport function warnLog(msg: string, n?: string) {\n  console.warn(`${n || 'wind-layer'}: ${msg}`);\n}\n\nconst warnings = {};\n\n/**\n * 在程序运行时只打印同类型警告一次\n * @param namespaces\n * @param msg\n */\nexport function warnOnce(namespaces: string, msg: string) {\n  if (!warnings[msg]) {\n    warnLog(msg, namespaces);\n    warnings[msg] = true;\n  }\n}\n\n/**\n * Get floored division\n * @param a\n * @param n\n * @returns {Number} returns remainder of floored division,\n * i.e., floor(a / n). Useful for consistent modulo of negative numbers.\n * See http://en.wikipedia.org/wiki/Modulo_operation.\n */\nexport function floorMod(a: number, n: number) {\n  return a - n * Math.floor(a / n);\n}\n\n/**\n * 检查值是否合法\n * @param val\n * @returns {boolean}\n */\nexport function isValide(val: any) {\n  return val !== undefined && val !== null && !isNaN(val);\n}\n\nexport interface IGFSItem {\n  header: {\n    parameterCategory: number | string;\n    parameterNumber: number | string;\n    dx: number;\n    dy: number;\n    nx: number;\n    ny: number;\n    lo1: number;\n    lo2: number;\n    la1: number;\n    la2: number;\n    [key: string]: any;\n  };\n  data: number[];\n}\n\n/**\n * format gfs json to vector\n * @param data\n * @param options\n */\nexport function formatData(data: IGFSItem[], options: Partial<IField> = {}) {\n  let uComp: IGFSItem = undefined as unknown as IGFSItem;\n  let vComp: IGFSItem = undefined as unknown as IGFSItem;\n\n  if ((process.env.NODE_ENV as string) === ('development' as string)) {\n    console.time('format-data');\n  }\n\n  data.forEach(function (record: IGFSItem) {\n    switch (record.header.parameterCategory + ',' + record.header.parameterNumber) {\n      case '1,2':\n      case '2,2':\n        uComp = record;\n        break;\n      case '1,3':\n      case '2,3':\n        vComp = record;\n        break;\n    }\n  });\n\n  if (!vComp || !uComp) {\n    return undefined;\n  }\n\n  const header = uComp.header;\n  const vectorField = new Field({\n    xmin: header.lo1, // 一般格点数据是按照矩形范围来切割，所以定义其经纬度范围\n    ymin: header.la1,\n    xmax: header.lo2,\n    ymax: header.la2,\n    deltaX: header.dx, // x（经度）增量\n    deltaY: header.dy, // y（维度）增量\n    cols: header.nx, // 列（可由 `(xmax - xmin) / deltaX` 得到）\n    rows: header.ny, // 行\n    us: uComp.data, // U分量\n    vs: vComp.data, // V分量\n    ...options,\n  });\n\n  if ((process.env.NODE_ENV as string) === ('development' as string)) {\n    console.timeEnd('format-data');\n  }\n\n  return vectorField;\n}\n\n/**\n * create canvas\n * @param width\n * @param height\n * @param retina\n * @param Canvas\n * @returns {HTMLCanvasElement}\n */\nexport function createCanvas(width: number, height: number, retina: number, Canvas?: any): HTMLCanvasElement {\n  if (typeof document !== 'undefined') {\n    const canvas = document.createElement('canvas');\n    canvas.width = width * retina;\n    canvas.height = height * retina;\n    return canvas;\n  } else {\n    // create a new canvas instance in node.js\n    // the canvas class needs to have a default constructor without any parameter\n    return new Canvas(width * retina, height * retina);\n  }\n}\n\n/**\n * 移除 dom\n * @param node\n * @returns {removeDomNode}\n */\nexport function removeDomNode(node: HTMLElement | HTMLCanvasElement) {\n  if (!node) {\n    return null;\n  }\n  if (node.parentNode) {\n    node.parentNode.removeChild(node);\n  }\n  return node;\n}\n\nconst keyword = /(\\D+)/;\nconst hex = /^#([a-f0-9]{6})([a-f0-9]{2})?$/i;\n// eslint-disable-next-line no-useless-escape\nconst rgba = /^rgba?\\(\\s*([+-]?\\d+)\\s*,\\s*([+-]?\\d+)\\s*,\\s*([+-]?\\d+)\\s*(?:,\\s*([+-]?[\\d.]+)\\s*)?\\)$/;\nconst colorNames: {\n  [key: string]: number[];\n} = {\n  aliceblue: [240, 248, 255],\n  antiquewhite: [250, 235, 215],\n  aqua: [0, 255, 255],\n  aquamarine: [127, 255, 212],\n  azure: [240, 255, 255],\n  beige: [245, 245, 220],\n  bisque: [255, 228, 196],\n  black: [0, 0, 0],\n  blanchedalmond: [255, 235, 205],\n  blue: [0, 0, 255],\n  blueviolet: [138, 43, 226],\n  brown: [165, 42, 42],\n  burlywood: [222, 184, 135],\n  cadetblue: [95, 158, 160],\n  chartreuse: [127, 255, 0],\n  chocolate: [210, 105, 30],\n  coral: [255, 127, 80],\n  cornflowerblue: [100, 149, 237],\n  cornsilk: [255, 248, 220],\n  crimson: [220, 20, 60],\n  cyan: [0, 255, 255],\n  darkblue: [0, 0, 139],\n  darkcyan: [0, 139, 139],\n  darkgoldenrod: [184, 134, 11],\n  darkgray: [169, 169, 169],\n  darkgreen: [0, 100, 0],\n  darkgrey: [169, 169, 169],\n  darkkhaki: [189, 183, 107],\n  darkmagenta: [139, 0, 139],\n  darkolivegreen: [85, 107, 47],\n  darkorange: [255, 140, 0],\n  darkorchid: [153, 50, 204],\n  darkred: [139, 0, 0],\n  darksalmon: [233, 150, 122],\n  darkseagreen: [143, 188, 143],\n  darkslateblue: [72, 61, 139],\n  darkslategray: [47, 79, 79],\n  darkslategrey: [47, 79, 79],\n  darkturquoise: [0, 206, 209],\n  darkviolet: [148, 0, 211],\n  deeppink: [255, 20, 147],\n  deepskyblue: [0, 191, 255],\n  dimgray: [105, 105, 105],\n  dimgrey: [105, 105, 105],\n  dodgerblue: [30, 144, 255],\n  firebrick: [178, 34, 34],\n  floralwhite: [255, 250, 240],\n  forestgreen: [34, 139, 34],\n  fuchsia: [255, 0, 255],\n  gainsboro: [220, 220, 220],\n  ghostwhite: [248, 248, 255],\n  gold: [255, 215, 0],\n  goldenrod: [218, 165, 32],\n  gray: [128, 128, 128],\n  green: [0, 128, 0],\n  greenyellow: [173, 255, 47],\n  grey: [128, 128, 128],\n  honeydew: [240, 255, 240],\n  hotpink: [255, 105, 180],\n  indianred: [205, 92, 92],\n  indigo: [75, 0, 130],\n  ivory: [255, 255, 240],\n  khaki: [240, 230, 140],\n  lavender: [230, 230, 250],\n  lavenderblush: [255, 240, 245],\n  lawngreen: [124, 252, 0],\n  lemonchiffon: [255, 250, 205],\n  lightblue: [173, 216, 230],\n  lightcoral: [240, 128, 128],\n  lightcyan: [224, 255, 255],\n  lightgoldenrodyellow: [250, 250, 210],\n  lightgray: [211, 211, 211],\n  lightgreen: [144, 238, 144],\n  lightgrey: [211, 211, 211],\n  lightpink: [255, 182, 193],\n  lightsalmon: [255, 160, 122],\n  lightseagreen: [32, 178, 170],\n  lightskyblue: [135, 206, 250],\n  lightslategray: [119, 136, 153],\n  lightslategrey: [119, 136, 153],\n  lightsteelblue: [176, 196, 222],\n  lightyellow: [255, 255, 224],\n  lime: [0, 255, 0],\n  limegreen: [50, 205, 50],\n  linen: [250, 240, 230],\n  magenta: [255, 0, 255],\n  maroon: [128, 0, 0],\n  mediumaquamarine: [102, 205, 170],\n  mediumblue: [0, 0, 205],\n  mediumorchid: [186, 85, 211],\n  mediumpurple: [147, 112, 219],\n  mediumseagreen: [60, 179, 113],\n  mediumslateblue: [123, 104, 238],\n  mediumspringgreen: [0, 250, 154],\n  mediumturquoise: [72, 209, 204],\n  mediumvioletred: [199, 21, 133],\n  midnightblue: [25, 25, 112],\n  mintcream: [245, 255, 250],\n  mistyrose: [255, 228, 225],\n  moccasin: [255, 228, 181],\n  navajowhite: [255, 222, 173],\n  navy: [0, 0, 128],\n  oldlace: [253, 245, 230],\n  olive: [128, 128, 0],\n  olivedrab: [107, 142, 35],\n  orange: [255, 165, 0],\n  orangered: [255, 69, 0],\n  orchid: [218, 112, 214],\n  palegoldenrod: [238, 232, 170],\n  palegreen: [152, 251, 152],\n  paleturquoise: [175, 238, 238],\n  palevioletred: [219, 112, 147],\n  papayawhip: [255, 239, 213],\n  peachpuff: [255, 218, 185],\n  peru: [205, 133, 63],\n  pink: [255, 192, 203],\n  plum: [221, 160, 221],\n  powderblue: [176, 224, 230],\n  purple: [128, 0, 128],\n  rebeccapurple: [102, 51, 153],\n  red: [255, 0, 0],\n  rosybrown: [188, 143, 143],\n  royalblue: [65, 105, 225],\n  saddlebrown: [139, 69, 19],\n  salmon: [250, 128, 114],\n  sandybrown: [244, 164, 96],\n  seagreen: [46, 139, 87],\n  seashell: [255, 245, 238],\n  sienna: [160, 82, 45],\n  silver: [192, 192, 192],\n  skyblue: [135, 206, 235],\n  slateblue: [106, 90, 205],\n  slategray: [112, 128, 144],\n  slategrey: [112, 128, 144],\n  snow: [255, 250, 250],\n  springgreen: [0, 255, 127],\n  steelblue: [70, 130, 180],\n  tan: [210, 180, 140],\n  teal: [0, 128, 128],\n  thistle: [216, 191, 216],\n  tomato: [255, 99, 71],\n  turquoise: [64, 224, 208],\n  violet: [238, 130, 238],\n  wheat: [245, 222, 179],\n  white: [255, 255, 255],\n  whitesmoke: [245, 245, 245],\n  yellow: [255, 255, 0],\n  yellowgreen: [154, 205, 50],\n};\n\nexport function getColor(string: string) {\n  let rgb: any[] = [];\n\n  if (string.match(hex)) {\n    let match = string.match(hex);\n\n    if (match !== null) {\n      // @ts-ignore\n      match = match[1];\n\n      for (let i = 0; i < 3; i++) {\n        // https://jsperf.com/slice-vs-substr-vs-substring-methods-long-string/19\n        const i2 = i * 2;\n        // @ts-ignore\n        rgb[i] = parseInt(match.slice(i2, i2 + 2), 16);\n      }\n\n      rgb[3] = 1;\n    }\n  } else if (string.match(rgba)) {\n    const match = string.match(rgba);\n    for (let i = 0; i < 3; i++) {\n      // @ts-ignore\n      rgb[i] = parseInt(match[i + 1], 0);\n    }\n\n    // @ts-ignore\n    if (match[4]) {\n      // @ts-ignore\n      rgb[3] = parseFloat(match[4]);\n    } else {\n      rgb[3] = 1;\n    }\n  } else if (string.match(keyword)) {\n    const match = string.match(keyword);\n    // @ts-ignore\n    if (match[1] === 'transparent') {\n      return [0, 0, 0, 0];\n    }\n    // @ts-ignore\n    rgb = colorNames[match[1]];\n    if (!rgb) {\n      return null;\n    }\n    rgb[3] = 1;\n    return rgb;\n  } else {\n    return null;\n  }\n\n  return rgb;\n}\n\nexport function compareVersion(v1, v2) {\n  // eslint-disable-next-line no-param-reassign\n  v1 = v1.split('.');\n  // eslint-disable-next-line no-param-reassign\n  v2 = v2.split('.');\n  const len = Math.max(v1.length, v2.length);\n\n  while (v1.length < len) {\n    v1.push('0');\n  }\n  while (v2.length < len) {\n    v2.push('0');\n  }\n\n  for (let i = 0; i < len; i++) {\n    const num1 = parseInt(v1[i]);\n    const num2 = parseInt(v2[i]);\n\n    if (num1 > num2) {\n      return 1;\n    } else if (num1 < num2) {\n      return -1;\n    }\n  }\n\n  return 0;\n}\n","export default class Vector {\n  public u: number;\n  public v: number;\n  public m: number;\n\n  constructor(u: number, v: number) {\n    this.u = u;\n    this.v = v;\n\n    this.m = this.magnitude();\n  }\n\n  /**\n   * 向量值（这里指风速）\n   * @returns {Number}\n   */\n  public magnitude() {\n    return Math.sqrt(this.u ** 2 + this.v ** 2);\n  }\n\n  /**\n   * 流体方向 （这里指风向，范围为0-360º）\n   * N is 0º and E is 90º\n   * @returns {Number}\n   */\n  public directionTo() {\n    const verticalAngle = Math.atan2(this.u, this.v);\n    let inDegrees = verticalAngle * (180.0 / Math.PI);\n    if (inDegrees < 0) {\n      inDegrees += 360.0;\n    }\n    return inDegrees;\n  }\n\n  /**\n   * Angle in degrees (0 to 360º) From x-->\n   * N is 0º and E is 90º\n   * @returns {Number}\n   */\n  public directionFrom() {\n    const a = this.directionTo();\n    return (a + 180.0) % 360.0;\n  }\n}\n","import { floorMod, warnOnce } from './utils';\nimport Vector from './Vector';\n\nexport interface IField {\n  /* 一般格点数据是按照矩形范围来切割，所以定义其经纬度范围 */\n\n  /**\n   * 经度最小值\n   */\n  xmin: number;\n\n  /**\n   * 纬度最小值\n   */\n  ymin: number;\n\n  /**\n   * 经度最大值\n   */\n  xmax: number;\n\n  /**\n   * 纬度最大值\n   */\n  ymax: number;\n\n  /**\n   * x（经度）增量\n   */\n  deltaX: number;\n\n  /**\n   * y（纬度）增量 (默认我们采用的数据和格点原始数据方向保持一致，数据从左上到右下) 但是需要注意的是此时 deltaY为 -(ymax-ymin) / rows\n   */\n  deltaY: number;\n\n  /**\n   * 列（可由 `(xmax - xmin) / deltaX` 得到）\n   */\n  cols: number;\n\n  /**\n   * 行\n   */\n  rows: number;\n\n  /**\n   * U分量\n   */\n  us: number[];\n\n  /**\n   * V分量\n   */\n  vs: number[];\n\n  /**\n   * 因为grib2json的问题，我们需要翻转 Y 轴数据\n   */\n  flipY?: boolean;\n\n  /**\n   * 是否实现跨世界渲染\n   */\n  wrapX?: boolean;\n\n  /**\n   * 当数据范围时按照 [0, 360] 时需要对x方向进行切割转换为 [-180, 180]，即将废弃\n   */\n  wrappedX?: boolean;\n\n  /**\n   * 当数据范围时按照 [0, 360] 时需要对x方向进行切割转换为 [-180, 180]\n   */\n  translateX?: boolean;\n}\n\nexport interface IPosition {\n  age?: number;\n  x?: number;\n  y?: number;\n  xt?: number;\n  yt?: number;\n  m?: number;\n}\n\nexport default class Field {\n  private readonly xmin: number;\n  private readonly xmax: number;\n  private readonly ymin: number;\n  private readonly ymax: number;\n  private readonly cols: number;\n  private readonly rows: number;\n  private readonly us: number[];\n  private readonly vs: number[];\n  private readonly isContinuous: boolean;\n  private readonly deltaY: number;\n  private readonly deltaX: number;\n  private readonly translateX: undefined | boolean;\n  private readonly isFields: boolean;\n  private readonly flipY: boolean;\n  public grid: (Vector | null)[][];\n  public range: (number | undefined)[] | undefined;\n  private wrapX: boolean;\n\n  constructor(params: IField) {\n    this.grid = [];\n\n    this.xmin = params.xmin;\n    this.xmax = params.xmax;\n\n    this.ymin = params.ymin;\n    this.ymax = params.ymax;\n\n    this.cols = params.cols; // 列数\n    this.rows = params.rows; // 行数\n\n    this.us = params.us; //\n    this.vs = params.vs;\n\n    this.deltaX = params.deltaX; // x 方向增量\n    this.deltaY = params.deltaY; // y方向增量\n    this.flipY = Boolean(params.flipY);\n\n    // 由于数据组织方式和deltaY的默认处理，那么在正常情况下我们需要交换 ymin 和 ymax 得到数据真实的 bbox（todo：我们需要按照真实数据来组织吗？）\n    this.ymin = Math.min(params.ymax, params.ymin);\n    this.ymax = Math.max(params.ymax, params.ymin);\n\n    // 当 deltaY < 0 时，但是数据组织是由左上到右下此时说明数据 Y 轴是反的\n    if (!(this.deltaY < 0 && this.ymin < this.ymax)) {\n      if (params.flipY === undefined) {\n        this.flipY = true;\n      }\n      console.warn('[wind-core]: The data is flipY');\n    }\n\n    /**\n     *\n     */\n    this.isFields = true;\n\n    const cols = Math.ceil((this.xmax - this.xmin) / params.deltaX); // 列\n    const rows = Math.ceil((this.ymax - this.ymin) / params.deltaY); // 行\n\n    if (cols !== this.cols || rows !== this.rows) {\n      console.warn('[wind-core]: The data grid not equal');\n    }\n\n    // 部分数据可能并不是连续的，其经度范围可能是 -180 - 179.5（比如 GFS 0.5 分辨率的）我们需要补齐最后一位\n    this.isContinuous = Math.floor(this.cols * params.deltaX) >= 360;\n    this.translateX = 'translateX' in params ? params.translateX : this.xmax > 180; // [0, 360] --> [-180, 180];\n    if ('wrappedX' in params) {\n      warnOnce('[wind-core]: ', '`wrappedX` namespace will deprecated please use `translateX` instead！');\n    }\n\n    this.wrapX = Boolean(params.wrapX);\n\n    this.grid = this.buildGrid();\n    this.range = this.calculateRange();\n  }\n\n  // from https://github.com/sakitam-fdd/wind-layer/blob/95368f9433/src/windy/windy.js#L110\n  public buildGrid(): (Vector | null)[][] {\n    const grid: any[] = [];\n    let p = 0;\n\n    const { rows, cols, us, vs } = this;\n\n    for (let j = 0; j < rows; j++) {\n      const row: any[] = [];\n      for (let i = 0; i < cols; i++, p++) {\n        const u = us[p];\n        const v = vs[p];\n        const valid = this.isValid(u) && this.isValid(v);\n        row[i] = valid ? new Vector(u, v) : null;\n      }\n\n      if (this.isContinuous) {\n        row.push(row[0]);\n      }\n\n      grid[j] = row;\n    }\n    return grid;\n  }\n\n  /**\n   * release data\n   */\n  public release() {\n    this.grid = [];\n  }\n\n  /**\n   * grib data extent\n   * 格点数据范围\n   */\n  public extent() {\n    return [this.xmin, this.ymin, this.xmax, this.ymax];\n  }\n\n  /**\n   * Bilinear interpolation for Vector\n   * 针对向量进行双线性插值\n   * https://en.wikipedia.org/wiki/Bilinear_interpolation\n   * @param   {Number} x\n   * @param   {Number} y\n   * @param   {Number[]} g00\n   * @param   {Number[]} g10\n   * @param   {Number[]} g01\n   * @param   {Number[]} g11\n   * @returns {Vector}\n   */\n  private bilinearInterpolateVector(\n    x: number,\n    y: number,\n    g00: { u: number; v: number },\n    g10: { u: number; v: number },\n    g01: { u: number; v: number },\n    g11: { u: number; v: number },\n  ) {\n    const rx = 1 - x;\n    const ry = 1 - y;\n\n    const a = rx * ry;\n    const b = x * ry;\n    const c = rx * y;\n    const d = x * y;\n    const u = g00.u * a + g10.u * b + g01.u * c + g11.u * d;\n    const v = g00.v * a + g10.v * b + g01.v * c + g11.v * d;\n    return new Vector(u, v);\n  }\n\n  /**\n   * calculate vector value range\n   */\n  calculateRange() {\n    if (!this.grid || !this.grid[0]) return;\n    const rows = this.grid.length as number;\n    const cols = this.grid[0].length as number;\n\n    // const vectors = [];\n    let min;\n    let max;\n    // @from: https://stackoverflow.com/questions/13544476/how-to-find-max-and-min-in-array-using-minimum-comparisons\n    for (let j = 0; j < rows; j++) {\n      for (let i = 0; i < cols; i++) {\n        const vec = this.grid[j][i];\n\n        if (vec !== null) {\n          const val = vec.m || vec.magnitude();\n          // vectors.push();\n          if (min === undefined) {\n            min = val;\n          } else if (max === undefined) {\n            max = val;\n            // update min max\n            // 1. Pick 2 elements(a, b), compare them. (say a > b)\n            min = Math.min(min, max);\n            max = Math.max(min, max);\n          } else {\n            // 2. Update min by comparing (min, b)\n            // 3. Update max by comparing (max, a)\n            min = Math.min(val, min);\n            max = Math.max(val, max);\n          }\n        }\n      }\n    }\n    return [min, max];\n  }\n\n  /**\n   * 检查 uv是否合法\n   * @param x\n   * @private\n   */\n  public isValid(x: any) {\n    return x !== null && x !== undefined;\n  }\n\n  private getWrappedLongitudes() {\n    let xmin = this.xmin;\n    let xmax = this.xmax;\n\n    if (this.translateX) {\n      if (this.isContinuous) {\n        xmin = -180;\n        xmax = 180;\n      } else {\n        // not sure about this (just one particular case, but others...?)\n        xmax = this.xmax - 360;\n        xmin = this.xmin - 360;\n      }\n    }\n    return [xmin, xmax];\n  }\n\n  public contains(lon: number, lat: number) {\n    const [xmin, xmax] = this.getWrappedLongitudes();\n\n    if (xmax > 180 && lon >= -180 && lon <= xmax - 360) {\n      lon += 360;\n    } else if (xmin < -180 && lon <= 180 && lon >= xmin + 360) {\n      lon -= 360;\n    }\n\n    const longitudeIn = lon >= xmin && lon <= xmax;\n    let latitudeIn;\n    if (this.deltaY >= 0) {\n      latitudeIn = lat >= this.ymin && lat <= this.ymax;\n    } else {\n      latitudeIn = lat >= this.ymax && lat <= this.ymin;\n    }\n    return longitudeIn && latitudeIn;\n  }\n\n  /**\n   * 获取经纬度所在的位置索引\n   * @param lon\n   * @param lat\n   */\n  public getDecimalIndexes(lon: number, lat: number) {\n    const i = floorMod(lon - this.xmin, 360) / this.deltaX; // calculate longitude index in wrapped range [0, 360)\n    if (this.flipY) {\n      const j = (this.ymax - lat) / this.deltaY; // calculate latitude index in direction +90 to -90\n      return [i, j];\n    } else {\n      const j = (this.ymin + lat) / this.deltaY; // calculate latitude index in direction +90 to -90\n      return [i, j];\n    }\n  }\n\n  /**\n   * Nearest value at lon-lat coordinates\n   * 线性插值\n   * @param lon\n   * @param lat\n   */\n  public valueAt(lon: number, lat: number) {\n    let flag = false;\n\n    if (this.wrapX) {\n      flag = true;\n    } else if (this.contains(lon, lat)) {\n      flag = true;\n    }\n\n    if (!flag) return null;\n\n    const indexes = this.getDecimalIndexes(lon, lat);\n    const ii = Math.floor(indexes[0]);\n    const jj = Math.floor(indexes[1]);\n\n    const ci = this.clampColumnIndex(ii);\n    const cj = this.clampRowIndex(jj);\n\n    return this.valueAtIndexes(ci, cj);\n  }\n\n  /**\n   * Get interpolated grid value lon-lat coordinates\n   * 双线性插值\n   * @param lon\n   * @param lat\n   */\n  public interpolatedValueAt(lon: number, lat: number) {\n    let flag = false;\n\n    if (this.wrapX) {\n      flag = true;\n    } else if (this.contains(lon, lat)) {\n      flag = true;\n    }\n\n    if (!flag) return null;\n\n    const [i, j] = this.getDecimalIndexes(lon, lat);\n    return this.interpolatePoint(i, j);\n  }\n\n  public hasValueAt(lon: number, lat: number) {\n    const value = this.valueAt(lon, lat);\n    return value !== null;\n  }\n\n  /**\n   * 基于向量的双线性插值\n   * @param i\n   * @param j\n   */\n  private interpolatePoint(i: number, j: number) {\n    //         1      2           After converting λ and φ to fractional grid indexes i and j, we find the\n    //        fi  i   ci          four points 'G' that enclose point (i, j). These points are at the four\n    //         | =1.4 |           corners specified by the floor and ceiling of i and j. For example, given\n    //      ---G--|---G--- fj 8   i = 1.4 and j = 8.3, the four surrounding grid points are (1, 8), (2, 8),\n    //    j ___|_ .   |           (1, 9) and (2, 9).\n    //  =8.3   |      |\n    //      ---G------G--- cj 9   Note that for wrapped grids, the first column is duplicated as the last\n    //         |      |           column, so the index ci can be used without taking a modulo.\n    const indexes = this.getFourSurroundingIndexes(i, j);\n    const [fi, ci, fj, cj] = indexes;\n    const values = this.getFourSurroundingValues(fi, ci, fj, cj);\n    if (values) {\n      const [g00, g10, g01, g11] = values;\n      // @ts-ignore\n      return this.bilinearInterpolateVector(i - fi, j - fj, g00, g10, g01, g11);\n    }\n\n    return null;\n  }\n\n  /**\n   * Check the column index is inside the field,\n   * adjusting to min or max when needed\n   * @private\n   * @param   {Number} ii - index\n   * @returns {Number} i - inside the allowed indexes\n   */\n  private clampColumnIndex(ii: number) {\n    let i = ii;\n    if (ii < 0) {\n      i = 0;\n    }\n    const maxCol = this.cols - 1;\n    if (ii > maxCol) {\n      i = maxCol;\n    }\n    return i;\n  }\n\n  /**\n   * Check the row index is inside the field,\n   * adjusting to min or max when needed\n   * @private\n   * @param   {Number} jj index\n   * @returns {Number} j - inside the allowed indexes\n   */\n  private clampRowIndex(jj: number) {\n    let j = jj;\n    if (jj < 0) {\n      j = 0;\n    }\n    const maxRow = this.rows - 1;\n    if (jj > maxRow) {\n      j = maxRow;\n    }\n    return j;\n  }\n\n  /**\n   * 计算索引位置周围的数据\n   * @private\n   * @param   {Number} i - decimal index\n   * @param   {Number} j - decimal index\n   * @returns {Array} [fi, ci, fj, cj]\n   */\n  private getFourSurroundingIndexes(i: number, j: number) {\n    const fi = Math.floor(i); // 左\n    let ci = fi + 1; // 右\n    // duplicate colum to simplify interpolation logic (wrapped value)\n    if (this.isContinuous && ci >= this.cols) {\n      ci = 0;\n    }\n    ci = this.clampColumnIndex(ci);\n\n    const fj = this.clampRowIndex(Math.floor(j)); // 上 纬度方向索引（取整）\n    const cj = this.clampRowIndex(fj + 1); // 下\n\n    return [fi, ci, fj, cj];\n  }\n\n  /**\n   * Get four surrounding values or null if not available,\n   * from 4 integer indexes\n   * @private\n   * @param   {Number} fi\n   * @param   {Number} ci\n   * @param   {Number} fj\n   * @param   {Number} cj\n   * @returns {Array}\n   */\n  private getFourSurroundingValues(fi: number, ci: number, fj: number, cj: number) {\n    let row;\n    if ((row = this.grid[fj])) {\n      const g00 = row[fi]; // << left\n      const g10 = row[ci]; // right >>\n      if (this.isValid(g00) && this.isValid(g10) && (row = this.grid[cj])) {\n        // lower row vv\n        const g01 = row[fi]; // << left\n        const g11 = row[ci]; // right >>\n        if (this.isValid(g01) && this.isValid(g11)) {\n          return [g00, g10, g01, g11]; // 4 values found!\n        }\n      }\n    }\n    return null;\n  }\n\n  /**\n   * Value for grid indexes\n   * @param   {Number} i - column index (integer)\n   * @param   {Number} j - row index (integer)\n   * @returns {Vector|Number}\n   */\n  public valueAtIndexes(i: number, j: number) {\n    return this.grid[j][i]; // <-- j,i !!\n  }\n\n  /**\n   * Lon-Lat for grid indexes\n   * @param   {Number} i - column index (integer)\n   * @param   {Number} j - row index (integer)\n   * @returns {Number[]} [lon, lat]\n   */\n  public lonLatAtIndexes(i: number, j: number) {\n    const lon = this.longitudeAtX(i);\n    const lat = this.latitudeAtY(j);\n\n    return [lon, lat];\n  }\n\n  /**\n   * Longitude for grid-index\n   * @param   {Number} i - column index (integer)\n   * @returns {Number} longitude at the center of the cell\n   */\n  private longitudeAtX(i: number) {\n    const halfXPixel = this.deltaX / 2.0;\n    let lon = this.xmin + halfXPixel + i * this.deltaX;\n    if (this.translateX) {\n      lon = lon > 180 ? lon - 360 : lon;\n    }\n    return lon;\n  }\n\n  /**\n   * Latitude for grid-index\n   * @param   {Number} j - row index (integer)\n   * @returns {Number} latitude at the center of the cell\n   */\n  private latitudeAtY(j: number) {\n    const halfYPixel = this.deltaY / 2.0;\n    return this.ymax - halfYPixel - j * this.deltaY;\n  }\n\n  /**\n   * 生成粒子位置\n   * @param o\n   * @param width\n   * @param height\n   * @param unproject\n   * @return IPosition\n   */\n  public randomize(\n    o: IPosition = {},\n    width: number,\n    height: number,\n    unproject: (a: number[]) => [number, number] | null,\n  ) {\n    const i = (Math.random() * (width || this.cols)) | 0;\n    const j = (Math.random() * (height || this.rows)) | 0;\n\n    const coords = unproject([i, j]);\n    if (coords !== null) {\n      o.x = coords[0];\n      o.y = coords[1];\n    } else {\n      o.x = this.longitudeAtX(i);\n      o.y = this.latitudeAtY(j);\n    }\n\n    return o;\n  }\n\n  /**\n   * 判断是否是 `Field` 的实例\n   * @return boolean\n   */\n  public checkFields() {\n    return this.isFields;\n  }\n}\n","import Field from './Field';\nimport type { IField } from './Field';\nimport Vector from './Vector';\nimport { isFunction, isNumber, isString, isValide } from './utils';\n\nexport const defaultOptions = {\n  globalAlpha: 0.9, // 全局透明度\n  lineWidth: 1, // 线条宽度\n  colorScale: '#fff',\n  velocityScale: 1 / 25,\n  // particleAge: 90,\n  maxAge: 90, // alias for particleAge\n  // particleMultiplier: 1 / 300, // TODO: PATHS = Math.round(width * height * particleMultiplier);\n  paths: 800,\n  frameRate: 20,\n  useCoordsDraw: true,\n};\n\ntype emptyFunc = (v?: any) => number;\n\nexport interface IOptions {\n  /**\n   * 全局透明度，主要影响粒子拖尾效果，默认 0.9\n   */\n  globalAlpha: number; // 全局透明度\n\n  /**\n   * 线条宽度\n   */\n  lineWidth: number | emptyFunc;\n\n  /**\n   * 粒子颜色配置, 默认#fff，当为回调函数时，参数 function(m:对应点风速值) => string\n   */\n  colorScale: string | string[] | emptyFunc;\n\n  /**\n   * 对于粒子路径步长的乘积系数，默认 1 / 25\n   */\n  velocityScale: number | emptyFunc;\n\n  /**\n   * 粒子路径能够生成的最大帧数，默认是 90\n   */\n  particleAge?: number; // 粒子在重新生成之前绘制的最大帧数\n\n  /**\n   * 粒子路径能够生成的最大帧数，默认是 90；他代表的是我们的 `paths` 数量的粒子的消亡控制，最小值是 0，最大值是 `maxAge`，在运行到 age 数时会消失然后进行重启\n   */\n  maxAge: number; // alias for particleAge\n\n  /**\n   * 粒子路径数量的系数，不推荐使用（视野宽度 * 高度 * 系数）\n   */\n  particleMultiplier?: number; // TODO: PATHS = Math.round(width * height * that.particleMultiplier);\n\n  /**\n   * 生成的粒子数量\n   */\n  paths: number | emptyFunc;\n\n  /**\n   * 用户自定义的帧率，默认是 20ms, 大概接近 50fps 帧，我们可能在某些场景需要降低帧率一保证渲染稳定性；注意此配置还会影响粒子运动的速度\n   */\n  frameRate: number;\n\n  /**\n   * 用户配置的风速最小值，如果未配置会从传入的数据中计算\n   */\n  minVelocity?: number;\n\n  /**\n   * 用户配置的风速最大值，如果未配置会从传入的数据中计算\n   */\n  maxVelocity?: number;\n\n  /**\n   * 使用外部传入的坐标系统，默认是 `true`；某些场景下我们可能直接使用像素坐标。\n   */\n  useCoordsDraw?: boolean;\n}\n\nfunction indexFor(m: number, min: number, max: number, colorScale: string[]) {\n  // map velocity speed to a style\n  return Math.max(0, Math.min(colorScale.length - 1, Math.round(((m - min) / (max - min)) * (colorScale.length - 1))));\n}\n\nclass WindCore {\n  public static Field = Field;\n\n  public forceStop: boolean;\n  private ctx: CanvasRenderingContext2D;\n  private options: IOptions;\n  private field: Field;\n  private particles: any[] = [];\n  private animationLoop: number;\n  private then: number;\n  private generated = false;\n\n  private starting: boolean;\n\n  constructor(ctx: CanvasRenderingContext2D, options: Partial<IOptions>, field?: Field) {\n    this.ctx = ctx;\n\n    if (!this.ctx) {\n      throw new Error('ctx error');\n    }\n\n    this.animate = this.animate.bind(this);\n\n    this.setOptions(options);\n\n    if (field) {\n      this.updateData(field);\n    }\n  }\n\n  /**\n   * 设置配置项\n   * @param options\n   */\n  public setOptions(options: Partial<IOptions>) {\n    this.options = { ...defaultOptions, ...options };\n\n    const { width, height } = this.ctx.canvas;\n\n    if ('particleAge' in options && !('maxAge' in options) && isNumber(this.options.particleAge)) {\n      // @ts-ignore\n      this.options.maxAge = this.options.particleAge;\n    }\n\n    if ('particleMultiplier' in options && !('paths' in options) && isNumber(this.options.particleMultiplier)) {\n      this.options.paths = Math.round(width * height * (this.options.particleMultiplier as number));\n    }\n\n    this.prerender();\n  }\n\n  /**\n   * 获取配置项\n   */\n  public getOptions() {\n    return this.options;\n  }\n\n  /**\n   * 更新数据\n   * @param field\n   */\n  public updateData(field: Field) {\n    this.field = field;\n    if (!this.generated) {\n      return;\n    }\n    this.particles = this.prepareParticlePaths();\n  }\n\n  // @ts-ignore\n  public project(...args: any[]): [number, number] | null {\n    throw new Error('project must be overriden');\n  }\n\n  // @ts-ignore\n  public unproject(...args: any[]): [number, number] | null {\n    throw new Error('unproject must be overriden');\n  }\n\n  /**\n   * 判断位置是否在当前视窗内\n   * @param coordinates\n   */\n  public intersectsCoordinate(coordinates: [number, number]): boolean {\n    throw new Error('must be overriden');\n  }\n\n  /**\n   * 清空当前画布\n   */\n  public clearCanvas() {\n    this.stop();\n    this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);\n    this.forceStop = false;\n  }\n\n  isStop() {\n    return !this.starting;\n  }\n\n  /**\n   * 启动粒子动画\n   */\n  public start() {\n    this.starting = true;\n    this.forceStop = false;\n    this.then = Date.now();\n    this.animate();\n  }\n\n  /**\n   * 停止粒子动画\n   */\n  public stop() {\n    cancelAnimationFrame(this.animationLoop);\n    this.starting = false;\n    this.forceStop = true;\n  }\n\n  public animate() {\n    if (this.animationLoop) {\n      cancelAnimationFrame(this.animationLoop);\n    }\n    this.animationLoop = requestAnimationFrame(this.animate);\n    const now = Date.now();\n    const delta = now - this.then;\n    if (delta > this.options.frameRate) {\n      this.then = now - (delta % this.options.frameRate);\n      this.render();\n    }\n  }\n\n  /**\n   * 渲染前处理\n   */\n  public prerender() {\n    this.generated = false;\n    if (!this.field) {\n      return;\n    }\n    this.particles = this.prepareParticlePaths();\n    this.generated = true;\n\n    if (!this.starting && !this.forceStop) {\n      this.starting = true;\n      this.then = Date.now();\n      this.animate();\n    }\n  }\n\n  /**\n   * 开始渲染\n   */\n  public render() {\n    this.moveParticles();\n    this.drawParticles();\n    this.postrender();\n  }\n\n  /**\n   * each frame render end\n   */\n  public postrender() {\n    //\n  }\n\n  private moveParticles() {\n    const { width, height } = this.ctx.canvas;\n    const particles = this.particles;\n    // 清空组\n    const maxAge = this.options.maxAge;\n    const velocityScale = isFunction(this.options.velocityScale)\n      ? this.options.velocityScale()\n      : this.options.velocityScale;\n\n    let i = 0;\n    const len = particles.length;\n    for (; i < len; i++) {\n      const particle = particles[i];\n\n      if (particle.age > maxAge) {\n        particle.age = 0;\n        // restart, on a random x,y\n        this.field.randomize(particle, width, height, this.unproject);\n      }\n\n      const x = particle.x;\n      const y = particle.y;\n\n      const vector = this.field.interpolatedValueAt(x, y);\n\n      if (vector === null) {\n        particle.age = maxAge;\n      } else {\n        const xt = x + vector.u * velocityScale;\n        const yt = y + vector.v * velocityScale;\n\n        if (this.field.hasValueAt(xt, yt)) {\n          // Path from (x,y) to (xt,yt) is visible, so add this particle to the appropriate draw bucket.\n          particle.xt = xt;\n          particle.yt = yt;\n          particle.m = vector.m;\n        } else {\n          // Particle isn't visible, but it still moves through the field.\n          particle.x = xt;\n          particle.y = yt;\n          particle.age = maxAge;\n        }\n      }\n\n      particle.age++;\n    }\n  }\n\n  private fadeIn() {\n    const prev = this.ctx.globalCompositeOperation; // lighter\n    this.ctx.globalCompositeOperation = 'destination-in';\n    this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);\n    this.ctx.globalCompositeOperation = prev;\n  }\n\n  private drawParticles() {\n    const particles = this.particles;\n    this.fadeIn();\n    this.ctx.globalAlpha = this.options.globalAlpha;\n\n    this.ctx.fillStyle = `rgba(0, 0, 0, ${this.options.globalAlpha})`;\n    this.ctx.lineWidth = (isNumber(this.options.lineWidth) ? this.options.lineWidth : 1) as number;\n    this.ctx.strokeStyle = (isString(this.options.colorScale) ? this.options.colorScale : '#fff') as string;\n\n    let i = 0;\n    const len = particles.length;\n    if (this.field && len > 0) {\n      let min: number;\n      let max: number;\n      // 如果配置了风速范围\n      if (isValide(this.options.minVelocity) && isValide(this.options.maxVelocity)) {\n        min = this.options.minVelocity as number;\n        max = this.options.maxVelocity as number;\n      } else {\n        // 未配置风速范围取格点数据中的最大风速和最小风速\n        [min, max] = this.field.range as [number, number];\n      }\n      for (; i < len; i++) {\n        this[this.options.useCoordsDraw ? 'drawCoordsParticle' : 'drawPixelParticle'](particles[i], min, max);\n      }\n    }\n  }\n\n  /**\n   * 用于绘制像素粒子\n   * @param particle\n   * @param min\n   * @param max\n   */\n  private drawPixelParticle(particle: any, min: number, max: number) {\n    // TODO 需要判断粒子是否超出视野\n    // this.ctx.strokeStyle = color;\n    const pointPrev: [number, number] = [particle.x, particle.y];\n    // when xt isn't exit\n    const pointNext: [number, number] = [particle.xt, particle.yt];\n\n    if (\n      pointNext &&\n      pointPrev &&\n      isValide(pointNext[0]) &&\n      isValide(pointNext[1]) &&\n      isValide(pointPrev[0]) &&\n      isValide(pointPrev[1]) &&\n      particle.age <= this.options.maxAge\n    ) {\n      this.ctx.beginPath();\n      this.ctx.moveTo(pointPrev[0], pointPrev[1]);\n      this.ctx.lineTo(pointNext[0], pointNext[1]);\n\n      if (isFunction(this.options.colorScale)) {\n        // @ts-ignore\n        this.ctx.strokeStyle = this.options.colorScale(particle.m) as string;\n      } else if (Array.isArray(this.options.colorScale)) {\n        const colorIdx = indexFor(particle.m, min, max, this.options.colorScale);\n        this.ctx.strokeStyle = this.options.colorScale[colorIdx];\n      }\n\n      if (isFunction(this.options.lineWidth)) {\n        // @ts-ignore\n        this.ctx.lineWidth = this.options.lineWidth(particle.m) as number;\n      }\n\n      particle.x = particle.xt;\n      particle.y = particle.yt;\n\n      this.ctx.stroke();\n    }\n  }\n\n  /**\n   * 用于绘制坐标粒子\n   * @param particle\n   * @param min\n   * @param max\n   */\n  private drawCoordsParticle(particle: any, min: number, max: number) {\n    // TODO 需要判断粒子是否超出视野\n    // this.ctx.strokeStyle = color;\n    const source: [number, number] = [particle.x, particle.y];\n    // when xt isn't exit\n    const target: [number, number] = [particle.xt, particle.yt];\n\n    if (\n      target &&\n      source &&\n      isValide(target[0]) &&\n      isValide(target[1]) &&\n      isValide(source[0]) &&\n      isValide(source[1]) &&\n      this.intersectsCoordinate(target) &&\n      particle.age <= this.options.maxAge\n    ) {\n      const pointPrev = this.project(source);\n      const pointNext = this.project(target);\n\n      if (pointPrev && pointNext) {\n        this.ctx.beginPath();\n        this.ctx.moveTo(pointPrev[0], pointPrev[1]);\n        this.ctx.lineTo(pointNext[0], pointNext[1]);\n        particle.x = particle.xt;\n        particle.y = particle.yt;\n\n        if (isFunction(this.options.colorScale)) {\n          // @ts-ignore\n          this.ctx.strokeStyle = this.options.colorScale(particle.m) as string;\n        } else if (Array.isArray(this.options.colorScale)) {\n          const colorIdx = indexFor(particle.m, min, max, this.options.colorScale);\n          this.ctx.strokeStyle = this.options.colorScale[colorIdx];\n        }\n\n        if (isFunction(this.options.lineWidth)) {\n          // @ts-ignore\n          this.ctx.lineWidth = this.options.lineWidth(particle.m) as number;\n        }\n\n        this.ctx.stroke();\n      }\n    }\n  }\n\n  private prepareParticlePaths() {\n    // 由用户自行处理，不再自动修改粒子数\n    const { width, height } = this.ctx.canvas;\n    const particleCount = typeof this.options.paths === 'function' ? this.options.paths(this) : this.options.paths;\n    const particles: any[] = [];\n    if (!this.field) {\n      return [];\n    }\n    let i = 0;\n    for (; i < particleCount; i++) {\n      particles.push(\n        this.field.randomize(\n          {\n            age: this.randomize(),\n          },\n          width,\n          height,\n          this.unproject,\n        ),\n      );\n    }\n    return particles;\n  }\n\n  private randomize() {\n    return Math.floor(Math.random() * this.options.maxAge);\n  }\n}\n\nexport * from './utils';\n\nexport { WindCore, Field, Vector, IField };\n","import type { Map } from 'ol';\nimport type { Coordinate } from 'ol/coordinate';\nimport type { Extent as IExtent } from 'ol/extent';\nimport { containsCoordinate } from 'ol/extent';\nimport { Image as ImageLayer } from 'ol/layer';\nimport type LayerType from 'ol/LayerType';\nimport type { Pixel as IPixel } from 'ol/pixel';\nimport type { ProjectionLike as IProjection } from 'ol/proj';\nimport { transform } from 'ol/proj';\nimport type { Size as ISize } from 'ol/size';\nimport type { Options as ImageCanvasOptions } from 'ol/source/ImageCanvas';\nimport ImageCanvas from 'ol/source/ImageCanvas';\nimport { WindCore, assign, createCanvas, defaultOptions, Field, formatData, isArray, warnLog } from 'wind-core';\n\nimport type { IOptions, IField } from 'wind-core';\n\nexport interface IWindOptions extends IOptions {\n  opacity?: number;\n  map?: Map;\n  visible?: boolean;\n  extent?: IExtent;\n  minResolution?: number;\n  maxResolution?: number;\n  zIndex?: number;\n  windOptions: Partial<IOptions>;\n  fieldOptions: Partial<IField>;\n  [key: string]: any;\n}\n\nconst _options = {\n  windOptions: {},\n};\n\nclass OlWind extends ImageLayer {\n  private options: IWindOptions;\n  private canvas: HTMLCanvasElement;\n  private wind: WindCore | null;\n  private field: Field | undefined;\n  private pixelRatio: number;\n  private viewProjection: IProjection;\n\n  constructor(data: any, options: Partial<IWindOptions> = {}) {\n    const opt = assign({}, _options, options);\n    // @ts-ignore todo need resolve\n    super(options);\n    this.options = opt;\n\n    /**\n     * windy layer\n     * @type {null}\n     */\n    this.wind = null;\n\n    this.type = 'IMAGE' as LayerType;\n\n    this.start = this.start.bind(this);\n    this.stop = this.stop.bind(this);\n\n    this.pickWindOptions();\n\n    const sourceOptions = {\n      logo: options.logo as string,\n      state: options.state,\n      attributions: options.attributions,\n      resolutions: options.resolutions,\n      canvasFunction: this.canvasFunction.bind(this),\n      // projection: (options.hasOwnProperty('projection') ? options.projection : 'EPSG:3857'),\n      ratio: options.hasOwnProperty('ratio') ? options.ratio : 1,\n    } as ImageCanvasOptions;\n\n    this.setSource(new ImageCanvas(sourceOptions));\n\n    if (data) {\n      this.setData(data, options.fieldOptions);\n    }\n  }\n\n  /**\n   * append layer to map\n   * @param map\n   */\n  public appendTo(map: Map) {\n    if (map) {\n      this.setMap(map);\n    } else {\n      throw new Error('not map object');\n    }\n  }\n\n  public start() {\n    if (this.wind) {\n      this.wind.start();\n    }\n  }\n\n  public stop() {\n    if (this.wind) {\n      this.wind.stop();\n    }\n  }\n\n  public canvasFunction(\n    extent: IExtent,\n    resolution: number,\n    pixelRatio: number,\n    size: ISize,\n    proj: IProjection, // eslint-disable-line\n  ): HTMLCanvasElement {\n    this.pixelRatio = pixelRatio;\n    if (!this.canvas) {\n      this.canvas = createCanvas(size[0], size[1], pixelRatio, null);\n    } else {\n      this.canvas.width = size[0];\n      this.canvas.height = size[1];\n    }\n\n    if (this.canvas) {\n      this.render(this.canvas);\n    }\n\n    return this.canvas;\n  }\n\n  private getContext() {\n    if (this.canvas === null) return;\n    return this.canvas.getContext('2d');\n  }\n\n  /**\n   * render windy layer\n   * @param canvas\n   * @returns {BMapWind}\n   */\n  private render(canvas: HTMLCanvasElement) {\n    const map = this.getMap();\n    if (!this.getData() || !map) return this;\n    const opt = this.getWindOptions();\n    if (canvas && !this.wind) {\n      const data = this.getData();\n\n      const ctx = this.getContext();\n\n      if (ctx) {\n        this.wind = new WindCore(ctx, opt, data);\n\n        this.wind.project = this.project.bind(this);\n        this.wind.unproject = this.unproject.bind(this);\n        this.wind.intersectsCoordinate = this.intersectsCoordinate.bind(this);\n        this.wind.postrender = () => {\n          this.changed();\n        };\n      }\n    }\n\n    if (this.wind) {\n      this.wind.prerender();\n      this.wind.render();\n    }\n\n    return this;\n  }\n\n  public project(coordinate: Coordinate): [number, number] {\n    const map = this.getMap();\n    const pixel = map.getPixelFromCoordinate(transform(coordinate, 'EPSG:4326', this.viewProjection));\n    return [pixel[0] * this.pixelRatio, pixel[1] * this.pixelRatio];\n  }\n\n  public unproject(pixel: IPixel): [number, number] {\n    const map = this.getMap();\n    const coordinates = map.getCoordinateFromPixel(pixel);\n    return transform(coordinates, this.viewProjection, 'EPSG:4326') as [number, number];\n  }\n\n  public intersectsCoordinate(coordinate: Coordinate): boolean {\n    const map = this.getMap();\n    if (!map) return false;\n    const view = map.getView();\n    const size = map.getSize();\n    if (view && size) {\n      const extent = view.calculateExtent([size[0] * this.pixelRatio, size[1] * this.pixelRatio]);\n      return containsCoordinate(extent, transform(coordinate, 'EPSG:4326', this.viewProjection));\n    }\n    return false;\n  }\n\n  private pickWindOptions() {\n    Object.keys(defaultOptions).forEach((key: string) => {\n      if (key in this.options) {\n        if (this.options.windOptions === undefined) {\n          this.options.windOptions = {};\n        }\n        // @ts-ignore todo need resolve\n        this.options.windOptions[key] = this.options[key];\n      }\n    });\n  }\n\n  /**\n   * get wind layer data\n   */\n  public getData() {\n    return this.field;\n  }\n\n  /**\n   * set layer data\n   * @param data\n   * @param options\n   * @returns {OlWind}\n   */\n  public setData(data: any, options: Partial<IField> = {}) {\n    if (data && data.checkFields && data.checkFields()) {\n      this.field = data;\n    } else if (isArray(data)) {\n      this.field = formatData(data, options);\n    } else {\n      console.error('Illegal data');\n    }\n\n    const map = this.getMap();\n\n    if (map && this.canvas && this.field) {\n      this?.wind?.updateData(this.field);\n      this.render(this.canvas);\n    }\n\n    return this;\n  }\n\n  public updateParams(options: Partial<IOptions> = {}) {\n    warnLog('will move to setWindOptions');\n    this.setWindOptions(options);\n    return this;\n  }\n\n  public getParams() {\n    warnLog('will move to getWindOptions');\n    return this.getWindOptions();\n  }\n\n  public setWindOptions(options: Partial<IOptions>) {\n    const beforeOptions = this.options.windOptions || {};\n    this.options = assign(this.options, {\n      windOptions: assign(beforeOptions, options || {}),\n    });\n\n    if (this.wind) {\n      this.wind.setOptions(this.options.windOptions);\n      this.wind.prerender();\n    }\n  }\n\n  public getWindOptions() {\n    return this.options.windOptions || {};\n  }\n\n  private getProjection() {\n    let projection;\n    const map = this.getMap();\n    // tslint:disable-next-line: prefer-conditional-expression\n    if (map) {\n      projection = map.getView() && map.getView().getProjection();\n    } else {\n      projection = 'EPSG:3857';\n    }\n    return projection;\n  }\n\n  /**\n   * set map\n   * @param map\n   */\n  public setMap(map: any) {\n    if (!map && this.wind) {\n      this.wind.stop();\n    }\n    this.set('originMap', map);\n    this.viewProjection = this.getProjection();\n    return super.setMap(map);\n  }\n\n  /**\n   * get map\n   */\n  public getMap() {\n    return this.get('originMap');\n  }\n\n  public getType(): LayerType {\n    return this.type;\n  }\n}\n\nconst WindLayer = OlWind;\n\nexport { Field, WindLayer };\n\nexport default OlWind;\n"]}