• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

可视化,mapboxGL加载台风风场动画

武飞扬头像
欧米ga
帮助1

学新通

这张酷似《星月夜》的气象数据——风场可视化地图是怎么做的? 在网上搜集了很多篇文章,今天总结出了使用最简单的方法,源码都在这了

核心代码

  1.  
  2.  
    var Windy = function Windy(params) {
  3.  
    var MIN_VELOCITY_INTENSITY = params.minVelocity || 0; // velocity at which particle intensity is minimum (m/s)
  4.  
     
  5.  
    var MAX_VELOCITY_INTENSITY = params.maxVelocity || 10; // velocity at which particle intensity is maximum (m/s)
  6.  
     
  7.  
    var VELOCITY_SCALE = (params.velocityScale || 0.005) * (Math.pow(window.devicePixelRatio, 1 / 3) || 1); // scale for wind velocity (completely arbitrary--this value looks nice)
  8.  
     
  9.  
    var MAX_PARTICLE_AGE = params.particleAge || 90; // max number of frames a particle is drawn before regeneration
  10.  
     
  11.  
    var PARTICLE_LINE_WIDTH = params.lineWidth || 1; // line width of a drawn particle
  12.  
     
  13.  
    var PARTICLE_MULTIPLIER = params.particleMultiplier || 1 / 300; // particle count scalar (completely arbitrary--this values looks nice)
  14.  
     
  15.  
    var PARTICLE_REDUCTION = Math.pow(window.devicePixelRatio, 1 / 3) || 1.6; // multiply particle count for mobiles by this amount
  16.  
     
  17.  
    var FRAME_RATE = params.frameRate || 15;
  18.  
    var FRAME_TIME = 1000 / FRAME_RATE; // desired frames per second
  19.  
     
  20.  
    var OPACITY = 0.97;
  21.  
    var defaulColorScale = ["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)"];
  22.  
    var colorScale = params.colorScale || defaulColorScale;
  23.  
    var NULL_WIND_VECTOR = [NaN, NaN, null]; // singleton for no wind in the form: [u, v, magnitude]
  24.  
     
  25.  
    var builder;
  26.  
    var grid;
  27.  
    var gridData = params.data;
  28.  
    var date;
  29.  
    var λ0, φ0, Δλ, Δφ, ni, nj;
  30.  
     
  31.  
    var setData = function setData(data) {
  32.  
    gridData = data;
  33.  
    };
  34.  
     
  35.  
    var setOptions = function setOptions(options) {
  36.  
    if (options.hasOwnProperty("minVelocity")) MIN_VELOCITY_INTENSITY = options.minVelocity;
  37.  
    if (options.hasOwnProperty("maxVelocity")) MAX_VELOCITY_INTENSITY = options.maxVelocity;
  38.  
    if (options.hasOwnProperty("velocityScale")) VELOCITY_SCALE = (options.velocityScale || 0.005) * (Math.pow(window.devicePixelRatio, 1 / 3) || 1);
  39.  
    if (options.hasOwnProperty("particleAge")) MAX_PARTICLE_AGE = options.particleAge;
  40.  
    if (options.hasOwnProperty("lineWidth")) PARTICLE_LINE_WIDTH = options.lineWidth;
  41.  
    if (options.hasOwnProperty("particleMultiplier")) PARTICLE_MULTIPLIER = options.particleMultiplier;
  42.  
    if (options.hasOwnProperty("opacity")) OPACITY = options.opacity;
  43.  
    if (options.hasOwnProperty("frameRate")) FRAME_RATE = options.frameRate;
  44.  
    FRAME_TIME = 1000 / FRAME_RATE;
  45.  
    }; // interpolation for vectors like wind (u,v,m)
  46.  
     
  47.  
     
  48.  
    var bilinearInterpolateVector = function bilinearInterpolateVector(x, y, g00, g10, g01, g11) {
  49.  
    var rx = 1 - x;
  50.  
    var ry = 1 - y;
  51.  
    var a = rx * ry,
  52.  
    b = x * ry,
  53.  
    c = rx * y,
  54.  
    d = x * y;
  55.  
    var u = g00[0] * a g10[0] * b g01[0] * c g11[0] * d;
  56.  
    var v = g00[1] * a g10[1] * b g01[1] * c g11[1] * d;
  57.  
    return [u, v, Math.sqrt(u * u v * v)];
  58.  
    };
  59.  
     
  60.  
    var createWindBuilder = function createWindBuilder(uComp, vComp) {
  61.  
    var uData = uComp.data,
  62.  
    vData = vComp.data;
  63.  
    return {
  64.  
    header: uComp.header,
  65.  
    //recipe: recipeFor("wind-" uComp.header.surface1Value),
  66.  
    data: function data(i) {
  67.  
    return [uData[i], vData[i]];
  68.  
    },
  69.  
    interpolate: bilinearInterpolateVector
  70.  
    };
  71.  
    };
  72.  
     
  73.  
    var createBuilder = function createBuilder(data) {
  74.  
    var uComp = null,
  75.  
    vComp = null,
  76.  
    scalar = null;
  77.  
    data.forEach(function (record) {
  78.  
    switch (record.header.parameterCategory "," record.header.parameterNumber) {
  79.  
    case "1,2":
  80.  
    case "2,2":
  81.  
    uComp = record;
  82.  
    break;
  83.  
     
  84.  
    case "1,3":
  85.  
    case "2,3":
  86.  
    vComp = record;
  87.  
    break;
  88.  
     
  89.  
    default:
  90.  
    scalar = record;
  91.  
    }
  92.  
    });
  93.  
    return createWindBuilder(uComp, vComp);
  94.  
    };
  95.  
     
  96.  
    var buildGrid = function buildGrid(data, callback) {
  97.  
    var supported = true;
  98.  
    if (data.length < 2) supported = false;
  99.  
    if (!supported) console.log("Windy Error: data must have at least two components (u,v)");
  100.  
    builder = createBuilder(data);
  101.  
    var header = builder.header;
  102.  
    if (header.hasOwnProperty("gridDefinitionTemplate") && header.gridDefinitionTemplate != 0) supported = false;
  103.  
     
  104.  
    if (!supported) {
  105.  
    console.log("Windy Error: Only data with Latitude_Longitude coordinates is supported");
  106.  
    }
  107.  
     
  108.  
    supported = true; // reset for futher checks
  109.  
     
  110.  
    λ0 = header.lo1;
  111.  
    φ0 = header.la1; // the grid's origin (e.g., 0.0E, 90.0N)
  112.  
     
  113.  
    Δλ = header.dx;
  114.  
    Δφ = header.dy; // distance between grid points (e.g., 2.5 deg lon, 2.5 deg lat)
  115.  
     
  116.  
    ni = header.nx;
  117.  
    nj = header.ny; // number of grid points W-E and N-S (e.g., 144 x 73)
  118.  
     
  119.  
    if (header.hasOwnProperty("scanMode")) {
  120.  
    var scanModeMask = header.scanMode.toString(2);
  121.  
    scanModeMask = ('0' scanModeMask).slice(-8);
  122.  
    var scanModeMaskArray = scanModeMask.split('').map(Number).map(Boolean);
  123.  
    if (scanModeMaskArray[0]) Δλ = -Δλ;
  124.  
    if (scanModeMaskArray[1]) Δφ = -Δφ;
  125.  
    if (scanModeMaskArray[2]) supported = false;
  126.  
    if (scanModeMaskArray[3]) supported = false;
  127.  
    if (scanModeMaskArray[4]) supported = false;
  128.  
    if (scanModeMaskArray[5]) supported = false;
  129.  
    if (scanModeMaskArray[6]) supported = false;
  130.  
    if (scanModeMaskArray[7]) supported = false;
  131.  
    if (!supported) console.log("Windy Error: Data with scanMode: " header.scanMode " is not supported.");
  132.  
    }
  133.  
     
  134.  
    date = new Date(header.refTime);
  135.  
    date.setHours(date.getHours() header.forecastTime); // Scan modes 0, 64 allowed.
  136.  
    // http://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_table3-4.shtml
  137.  
     
  138.  
    grid = [];
  139.  
    var p = 0;
  140.  
    var isContinuous = Math.floor(ni * Δλ) >= 360;
  141.  
     
  142.  
    for (var j = 0; j < nj; j ) {
  143.  
    var row = [];
  144.  
     
  145.  
    for (var i = 0; i < ni; i , p ) {
  146.  
    row[i] = builder.data(p);
  147.  
    }
  148.  
     
  149.  
    if (isContinuous) {
  150.  
    // For wrapped grids, duplicate first column as last column to simplify interpolation logic
  151.  
    row.push(row[0]);
  152.  
    }
  153.  
     
  154.  
    grid[j] = row;
  155.  
    }
  156.  
     
  157.  
    callback({
  158.  
    date: date,
  159.  
    interpolate: interpolate
  160.  
    });
  161.  
    };
  162.  
    /**
  163.  
    * Get interpolated grid value from Lon/Lat position
  164.  
    * @param λ {Float} Longitude
  165.  
    * @param φ {Float} Latitude
  166.  
    * @returns {Object}
  167.  
    */
  168.  
     
  169.  
     
  170.  
    var interpolate = function interpolate(λ, φ) {
  171.  
    if (!grid) return null;
  172.  
    var i = floorMod(λ - λ0, 360) / Δλ; // calculate longitude index in wrapped range [0, 360)
  173.  
     
  174.  
    var j = (φ0 - φ) / Δφ; // calculate latitude index in direction 90 to -90
  175.  
     
  176.  
    var fi = Math.floor(i),
  177.  
    ci = fi 1;
  178.  
    var fj = Math.floor(j),
  179.  
    cj = fj 1;
  180.  
    var row;
  181.  
     
  182.  
    if (row = grid[fj]) {
  183.  
    var g00 = row[fi];
  184.  
    var g10 = row[ci];
  185.  
     
  186.  
    if (isValue(g00) && isValue(g10) && (row = grid[cj])) {
  187.  
    var g01 = row[fi];
  188.  
    var g11 = row[ci];
  189.  
     
  190.  
    if (isValue(g01) && isValue(g11)) {
  191.  
    // All four points found, so interpolate the value.
  192.  
    return builder.interpolate(i - fi, j - fj, g00, g10, g01, g11);
  193.  
    }
  194.  
    }
  195.  
    }
  196.  
     
  197.  
    return null;
  198.  
    };
  199.  
    /**
  200.  
    * @returns {Boolean} true if the specified value is not null and not undefined.
  201.  
    */
  202.  
     
  203.  
     
  204.  
    var isValue = function isValue(x) {
  205.  
    return x !== null && x !== undefined;
  206.  
    };
  207.  
    /**
  208.  
    * @returns {Number} returns remainder of floored division, i.e., floor(a / n). Useful for consistent modulo
  209.  
    * of negative numbers. See http://en.wikipedia.org/wiki/Modulo_operation.
  210.  
    */
  211.  
     
  212.  
     
  213.  
    var floorMod = function floorMod(a, n) {
  214.  
    return a - n * Math.floor(a / n);
  215.  
    };
  216.  
    /**
  217.  
    * @returns {Number} the value x clamped to the range [low, high].
  218.  
    */
  219.  
     
  220.  
     
  221.  
    var clamp = function clamp(x, range) {
  222.  
    return Math.max(range[0], Math.min(x, range[1]));
  223.  
    };
  224.  
    /**
  225.  
    * @returns {Boolean} true if agent is probably a mobile device. Don't really care if this is accurate.
  226.  
    */
  227.  
     
  228.  
     
  229.  
    var isMobile = function isMobile() {
  230.  
    return /android|blackberry|iemobile|ipad|iphone|ipod|opera mini|webos/i.test(navigator.userAgent);
  231.  
    };
  232.  
    /**
  233.  
    * Calculate distortion of the wind vector caused by the shape of the projection at point (x, y). The wind
  234.  
    * vector is modified in place and returned by this function.
  235.  
    */
  236.  
     
  237.  
     
  238.  
    var distort = function distort(projection, λ, φ, x, y, scale, wind) {
  239.  
    var u = wind[0] * scale;
  240.  
    var v = wind[1] * scale;
  241.  
    var d = distortion(projection, λ, φ, x, y); // Scale distortion vectors by u and v, then add.
  242.  
     
  243.  
    wind[0] = d[0] * u d[2] * v;
  244.  
    wind[1] = d[1] * u d[3] * v;
  245.  
    return wind;
  246.  
    };
  247.  
     
  248.  
    var distortion = function distortion(projection, λ, φ, x, y) {
  249.  
    var τ = 2 * Math.PI; // var H = Math.pow(10, -5.2); // 0.00000630957344480193
  250.  
    // var H = 0.0000360; // 0.0000360°φ ~= 4m (from https://github.com/cambecc/earth/blob/master/public/libs/earth/1.0.0/micro.js#L13)
  251.  
     
  252.  
    var H = 5; // ToDo: Why does this work?
  253.  
     
  254.  
    var hλ = λ < 0 ? H : -H;
  255.  
    var hφ = φ < 0 ? H : -H;
  256.  
    var pλ = project(φ, λ hλ);
  257.  
    var pφ = project(φ hφ, λ); // Meridian scale factor (see Snyder, equation 4-3), where R = 1. This handles issue where length of 1º λ
  258.  
    // changes depending on φ. Without this, there is a pinching effect at the poles.
  259.  
     
  260.  
    var k = Math.cos(φ / 360 * τ);
  261.  
    return [(pλ[0] - x) / hλ / k, (pλ[1] - y) / hλ / k, (pφ[0] - x) / hφ, (pφ[1] - y) / hφ];
  262.  
    };
  263.  
     
  264.  
    var createField = function createField(columns, bounds, callback) {
  265.  
    /**
  266.  
    * @returns {Array} wind vector [u, v, magnitude] at the point (x, y), or [NaN, NaN, null] if wind
  267.  
    * is undefined at that point.
  268.  
    */
  269.  
    function field(x, y) {
  270.  
    var column = columns[Math.round(x)];
  271.  
    return column && column[Math.round(y)] || NULL_WIND_VECTOR;
  272.  
    } // Frees the massive "columns" array for GC. Without this, the array is leaked (in Chrome) each time a new
  273.  
    // field is interpolated because the field closure's context is leaked, for reasons that defy explanation.
  274.  
     
  275.  
     
  276.  
    field.release = function () {
  277.  
    columns = [];
  278.  
    };
  279.  
     
  280.  
    field.randomize = function (o) {
  281.  
    // UNDONE: this method is terrible
  282.  
    var x, y;
  283.  
    var safetyNet = 0;
  284.  
     
  285.  
    do {
  286.  
    x = Math.round(Math.floor(Math.random() * bounds.width) bounds.x);
  287.  
    y = Math.round(Math.floor(Math.random() * bounds.height) bounds.y);
  288.  
    } while (field(x, y)[2] === null && safetyNet < 30);
  289.  
     
  290.  
    o.x = x;
  291.  
    o.y = y;
  292.  
    return o;
  293.  
    };
  294.  
     
  295.  
    callback(bounds, field);
  296.  
    };
  297.  
     
  298.  
    var buildBounds = function buildBounds(bounds, width, height) {
  299.  
    var upperLeft = bounds[0];
  300.  
    var lowerRight = bounds[1];
  301.  
    var x = Math.round(upperLeft[0]); //Math.max(Math.floor(upperLeft[0], 0), 0);
  302.  
     
  303.  
    var y = Math.max(Math.floor(upperLeft[1], 0), 0);
  304.  
    var xMax = Math.min(Math.ceil(lowerRight[0], width), width - 1);
  305.  
    var yMax = Math.min(Math.ceil(lowerRight[1], height), height - 1);
  306.  
    return {
  307.  
    x: x,
  308.  
    y: y,
  309.  
    xMax: width,
  310.  
    yMax: yMax,
  311.  
    width: width,
  312.  
    height: height
  313.  
    };
  314.  
    };
  315.  
     
  316.  
    var deg2rad = function deg2rad(deg) {
  317.  
    return deg / 180 * Math.PI;
  318.  
    };
  319.  
     
  320.  
    var invert = function invert(x, y, windy) {
  321.  
    var latlon = params.map.unproject([x, y]);
  322.  
    return [latlon.lng, latlon.lat];
  323.  
    };
  324.  
     
  325.  
    var project = function project(lat, lon, windy) {
  326.  
    var xy = params.map.project([lon, lat]);
  327.  
    return [xy.x, xy.y];
  328.  
    };
  329.  
     
  330.  
    var interpolateField = function interpolateField(grid, bounds, extent, callback) {
  331.  
    var projection = {}; // map.crs used instead
  332.  
     
  333.  
    var mapArea = (extent.south - extent.north) * (extent.west - extent.east);
  334.  
    var velocityScale = VELOCITY_SCALE * Math.pow(mapArea, 0.4);
  335.  
    var columns = [];
  336.  
    var x = bounds.x;
  337.  
     
  338.  
    function interpolateColumn(x) {
  339.  
    var column = [];
  340.  
     
  341.  
    for (var y = bounds.y; y <= bounds.yMax; y = 2) {
  342.  
    var coord = invert(x, y);
  343.  
     
  344.  
    if (coord) {
  345.  
    var λ = coord[0],
  346.  
    φ = coord[1];
  347.  
     
  348.  
    if (isFinite(λ)) {
  349.  
    var wind = grid.interpolate(λ, φ);
  350.  
     
  351.  
    if (wind) {
  352.  
    wind = distort(projection, λ, φ, x, y, velocityScale, wind);
  353.  
    column[y 1] = column[y] = wind;
  354.  
    }
  355.  
    }
  356.  
    }
  357.  
    }
  358.  
     
  359.  
    columns[x 1] = columns[x] = column;
  360.  
    }
  361.  
     
  362.  
    (function batchInterpolate() {
  363.  
    var start = Date.now();
  364.  
     
  365.  
    while (x < bounds.width) {
  366.  
    interpolateColumn(x);
  367.  
    x = 2;
  368.  
     
  369.  
    if (Date.now() - start > 1000) {
  370.  
    //MAX_TASK_TIME) {
  371.  
    setTimeout(batchInterpolate, 25);
  372.  
    return;
  373.  
    }
  374.  
    }
  375.  
     
  376.  
    createField(columns, bounds, callback);
  377.  
    })();
  378.  
    };
  379.  
     
  380.  
    var animationLoop;
  381.  
     
  382.  
    var animate = function animate(bounds, field) {
  383.  
    function windIntensityColorScale(min, max) {
  384.  
    colorScale.indexFor = function (m) {
  385.  
    // map velocity speed to a style
  386.  
    return Math.max(0, Math.min(colorScale.length - 1, Math.round((m - min) / (max - min) * (colorScale.length - 1))));
  387.  
    };
  388.  
     
  389.  
    return colorScale;
  390.  
    }
  391.  
     
  392.  
    var colorStyles = windIntensityColorScale(MIN_VELOCITY_INTENSITY, MAX_VELOCITY_INTENSITY);
  393.  
    var buckets = colorStyles.map(function () {
  394.  
    return [];
  395.  
    });
  396.  
    var particleCount = Math.round(bounds.width * bounds.height * PARTICLE_MULTIPLIER);
  397.  
     
  398.  
    if (isMobile()) {
  399.  
    particleCount *= PARTICLE_REDUCTION;
  400.  
    }
  401.  
     
  402.  
    var fadeFillStyle = "rgba(0, 0, 0, ".concat(OPACITY, ")");
  403.  
    var particles = [];
  404.  
     
  405.  
    for (var i = 0; i < particleCount; i ) {
  406.  
    particles.push(field.randomize({
  407.  
    age: Math.floor(Math.random() * MAX_PARTICLE_AGE) 0
  408.  
    }));
  409.  
    }
  410.  
     
  411.  
    function evolve() {
  412.  
    buckets.forEach(function (bucket) {
  413.  
    bucket.length = 0;
  414.  
    });
  415.  
    particles.forEach(function (particle) {
  416.  
    if (particle.age > MAX_PARTICLE_AGE) {
  417.  
    field.randomize(particle).age = 0;
  418.  
    }
  419.  
     
  420.  
    var x = particle.x;
  421.  
    var y = particle.y;
  422.  
    var v = field(x, y); // vector at current position
  423.  
     
  424.  
    var m = v[2];
  425.  
     
  426.  
    if (m === null) {
  427.  
    particle.age = MAX_PARTICLE_AGE; // particle has escaped the grid, never to return...
  428.  
    } else {
  429.  
    var xt = x v[0];
  430.  
    var yt = y v[1];
  431.  
     
  432.  
    if (field(xt, yt)[2] !== null) {
  433.  
    // Path from (x,y) to (xt,yt) is visible, so add this particle to the appropriate draw bucket.
  434.  
    particle.xt = xt;
  435.  
    particle.yt = yt;
  436.  
    buckets[colorStyles.indexFor(m)].push(particle);
  437.  
    } else {
  438.  
    // Particle isn't visible, but it still moves through the field.
  439.  
    particle.x = xt;
  440.  
    particle.y = yt;
  441.  
    }
  442.  
    }
  443.  
     
  444.  
    particle.age = 1;
  445.  
    });
  446.  
    }
  447.  
     
  448.  
    var g = params.canvas.getContext("2d");
  449.  
    g.lineWidth = PARTICLE_LINE_WIDTH;
  450.  
    g.fillStyle = fadeFillStyle;
  451.  
    g.globalAlpha = 0.6;
  452.  
     
  453.  
    function draw() {
  454.  
    // Fade existing particle trails.
  455.  
    var prev = "lighter";
  456.  
    g.globalCompositeOperation = "destination-in";
  457.  
    g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
  458.  
    g.globalCompositeOperation = prev;
  459.  
    g.globalAlpha = OPACITY === 0 ? 0 : OPACITY * 0.9; // Draw new particle trails.
  460.  
     
  461.  
    buckets.forEach(function (bucket, i) {
  462.  
    if (bucket.length > 0) {
  463.  
    g.beginPath();
  464.  
    g.strokeStyle = colorStyles[i];
  465.  
    bucket.forEach(function (particle) {
  466.  
    g.moveTo(particle.x, particle.y);
  467.  
    g.lineTo(particle.xt, particle.yt);
  468.  
    particle.x = particle.xt;
  469.  
    particle.y = particle.yt;
  470.  
    });
  471.  
    g.stroke();
  472.  
    }
  473.  
    });
  474.  
    }
  475.  
     
  476.  
    var then = Date.now();
  477.  
     
  478.  
    (function frame() {
  479.  
    animationLoop = requestAnimationFrame(frame);
  480.  
    var now = Date.now();
  481.  
    var delta = now - then;
  482.  
     
  483.  
    if (delta > FRAME_TIME) {
  484.  
    then = now - delta % FRAME_TIME;
  485.  
    evolve();
  486.  
    draw();
  487.  
    }
  488.  
    })();
  489.  
    };
  490.  
     
  491.  
    var start = function start(bounds, width, height, extent) {
  492.  
    var mapBounds = {
  493.  
    south: deg2rad(extent[0][1]),
  494.  
    north: deg2rad(extent[1][1]),
  495.  
    east: deg2rad(extent[1][0]),
  496.  
    west: deg2rad(extent[0][0]),
  497.  
    width: width,
  498.  
    height: height
  499.  
    };
  500.  
    stop(); // build grid
  501.  
     
  502.  
    buildGrid(gridData, function (grid) {
  503.  
    // interpolateField
  504.  
    interpolateField(grid, buildBounds(bounds, width, height), mapBounds, function (bounds, field) {
  505.  
    // animate the canvas with random points
  506.  
    windy.field = field;
  507.  
    animate(bounds, field);
  508.  
    });
  509.  
    });
  510.  
    };
  511.  
     
  512.  
    var stop = function stop() {
  513.  
    if (windy.field) windy.field.release();
  514.  
    if (animationLoop) cancelAnimationFrame(animationLoop);
  515.  
    };
  516.  
     
  517.  
    var windy = {
  518.  
    params: params,
  519.  
    start: start,
  520.  
    stop: stop,
  521.  
    createField: createField,
  522.  
    interpolatePoint: interpolate,
  523.  
    setData: setData,
  524.  
    setOptions: setOptions
  525.  
    };
  526.  
    return windy;
  527.  
    };
  528.  
     
  529.  
    if (!window.cancelAnimationFrame) {
  530.  
    window.cancelAnimationFrame = function (id) {
  531.  
    clearTimeout(id);
  532.  
    };
  533.  
    }
  534.  
     
  535.  
学新通

加载方法

  1.  
    var windyMap = {
  2.  
    windy: null,
  3.  
    map: null,
  4.  
    visible: true,
  5.  
    context: null,
  6.  
    timer: 0,
  7.  
    initWindy(data, map) {
  8.  
    const self = this;
  9.  
    self.visible = true;
  10.  
    self.map = map;
  11.  
     
  12.  
    // 删除dom
  13.  
    self.hideWind();
  14.  
     
  15.  
    let canvas = document.createElement('canvas');
  16.  
    canvas.id = 'windCanvas';
  17.  
    canvas.width = map.getCanvas().width;
  18.  
    canvas.height = map.getCanvas().height;
  19.  
    canvas.style.position = 'absolute';
  20.  
    canvas.style.top = 0;
  21.  
    canvas.style.left = 0;
  22.  
    map.getCanvasContainer().appendChild(canvas);
  23.  
    this.context = canvas.getContext("2d");
  24.  
     
  25.  
    self.windy = new Windy({
  26.  
    canvas: canvas,
  27.  
    data: data,
  28.  
    map: map
  29.  
    });
  30.  
     
  31.  
    if (self.timer) clearTimeout(self.timer);
  32.  
    this.timer = setTimeout(function () {
  33.  
    self._refreshWindy();
  34.  
    }, 750);
  35.  
     
  36.  
    map.on("dragstart", function(){
  37.  
    if(self.context) self.context.clearRect(0, 0, 3000, 3000);
  38.  
    self.windy.stop();
  39.  
    });
  40.  
     
  41.  
    map.on("dragend", function() {
  42.  
    self._refreshWindy();
  43.  
    });
  44.  
     
  45.  
    map.on("zoomstart", function(){
  46.  
    if(self.context) self.context.clearRect(0, 0, 3000, 3000);
  47.  
    self.windy.stop();
  48.  
    });
  49.  
     
  50.  
    map.on("zoomend", function() {
  51.  
    self._refreshWindy();
  52.  
    });
  53.  
     
  54.  
    map.on("resize", function() {
  55.  
    self.clearWind();
  56.  
    });
  57.  
    },
  58.  
    _refreshWindy: function() {
  59.  
    const self = this;
  60.  
    const _canvas = self.windy.params.canvas;
  61.  
    if (!self.windy) return;
  62.  
    let bounds = self.map.getBounds();
  63.  
    let extent = [
  64.  
    bounds._sw.lng,
  65.  
    bounds._sw.lat,
  66.  
    bounds._ne.lng,
  67.  
    bounds._ne.lat
  68.  
    ];
  69.  
     
  70.  
    _canvas.width = map.getCanvas().width;
  71.  
    _canvas.height = map.getCanvas().height;
  72.  
     
  73.  
    self.windy.start(
  74.  
    [[0, 0], [_canvas.width, _canvas.height]],
  75.  
    _canvas.width,
  76.  
    _canvas.height,
  77.  
    [[extent[0], extent[1]], [extent[2], extent[3]]]
  78.  
    );
  79.  
    },
  80.  
     
  81.  
    hideWind: function() {
  82.  
    if(this.context) this.context.clearRect(0, 0, 3000, 3000);
  83.  
    let dom = document.getElementById('windCanvas');
  84.  
    if (dom) dom.parentNode.removeChild(dom);
  85.  
    },
  86.  
     
  87.  
    clearWind: function() {
  88.  
    if (this.windy) this.windy.stop();
  89.  
    if(this.context) this.context.clearRect(0, 0, 3000, 3000);
  90.  
    },
  91.  
     
  92.  
    setVisible: function(flag) {
  93.  
    const self = this;
  94.  
    self.visible = flag;
  95.  
    let dom = document.getElementById('windCanvas');
  96.  
    if (!dom) return;
  97.  
    if (flag) {
  98.  
    dom.style.display = 'block';
  99.  
    self._refreshWindy();
  100.  
    } else {
  101.  
    if (self.windy) self.windy.stop();
  102.  
    dom.style.display = 'none';
  103.  
    }
  104.  
    }
  105.  
    };
学新通

调用

  1.  
    map.on('load', function() {
  2.  
    axios.get(`https://datacenter.istrongcloud.com/data/gfs/time_fc.json`, function(res) {
  3.  
     
  4.  
    axios.get(`https://datacenter.istrongcloud.com/data/gfs/fcdata/${res.data.data['024'].url}`).then(windRes => {
  5.  
    console.log('windRes: ', windRes.data);
  6.  
    windyMap.initWindy(Object.values(windRes.data)[0], map);
  7.  
    });
  8.  
    })
  9.  
    });

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhghafkg
系列文章
更多 icon
同类精品
更多 icon
继续加载