当我们做洋流或者风场 可视化时候 echart 虽然也能用 但是数据量过大会很卡

数据调用是这个样子

样例数据
链接: https://pan.baidu.com/s/1yQrIMBMJdSPwnnI8YOC1_Q 提取码: tnhc
最终调用

import {VectorField} from ‘./VectorField’;
// this.map 为arcgis Map对象实例
let vectorField = new VectorField(this.map);
const options = {
url: “./static/data/2020081106.json”,
displayOptions: {
minVelocity: 0, // 最小速度
maxVelocity: 10, // 最大速度
velocityScale: 0.005, // 速度
particleAge: 90, // 粒子生存的帧数
lineWidth: 0.5, // 线宽
frameRate: 15, // 运动帧率
particleDensity: 10, // 每50x50像素块的粒子数
colorScale: ["#ffffff", “#e9ecfb”, “#d3d9f7”, “#bdc6f3”, “#a7b3ef”, “#91a0eb”, “#7b8de7”, “#657ae3”, “#4f67df”, “#3954db”]
}
}
vectorField.start(options);
我们需要两个类

AnimatedEnvironmentLayer 类

import esriLoader from 'esri-loader';
export const AnimatedEnvironmentLayer = {}AnimatedEnvironmentLayer.create = function () {let a = null;
return new Promise(async (resolve, reject) => {const [asd, MapView, Map, Point, GraphicsLayer, SpatialReference, Basemap, esriRequest, on, dom, BaseLayerView2D, watchUtils, webMercatorUtils] = await (esriLoader.loadModules([
"esri/core/accessorSupport/decorators",
"esri/views/MapView",
"esri/Map",
"esri/geometry/Point",
"esri/layers/GraphicsLayer",
"esri/geometry/SpatialReference",
"esri/Basemap",
"esri/request",
"dojo/on",
"dojo/dom",
"esri/views/2d/layers/BaseLayerView2D",
"esri/core/watchUtils",
"esri/geometry/support/webMercatorUtils",
]));class AnimatedEnvironmentLayerView2D extends BaseLayerView2D {constructor(props) {super();
this.view = props.view;
this.layer = props.layer;this.view.on("resize", () => {if (!this.context) return;// resize the canvas
this.context.canvas.width = this.view.width;
this.context.canvas.height = this.view.height;
});watchUtils.watch(this.layer, "visible", (nv, olv, pn, ta) => {if (!nv) {this.clear();
} else {this.prepDraw();
}
});
}render(renderParameters) {this.viewState = renderParameters.state;if (!renderParameters.stationary) {// not stationary so clear if drawn and set to prep again
if (this.drawing) {this.clear();
this.drawing = false;
}
this.drawPrepping = false;
this.drawReady = false;
return;
}if (!this.drawPrepping && !this.drawReady) {// prep the draw
this.drawPrepping = true;
if (this.windy && this.windy.gridData) {this.prepDraw();
}
return;
}if (this.drawReady) {if (!this.drawing) {// this.animationLoop(); // haven't started drawing so kick off our animation loop
this.startWindy();
}// draw the custom context into this layers context
renderParameters.context.drawImage(this.context.canvas, 0, 0);
this.drawing = true;// call request render so we copy the draw again
this.requestRender();
}
}startWindy() {setTimeout(() => {this.windy.start(
[[0, 0], [this.context.canvas.width, this.context.canvas.height]],
this.context.canvas.width,
this.context.canvas.height,
[[this.southWest.x, this.southWest.y], [this.northEast.x, this.northEast.y]]
);this.setDate();
}, 500);
}attach() {// use attach to initilaize a custom canvas to draw on
// create the canvas, set some properties.
const canvas = document.createElement("canvas");
canvas.id = "ael-" + Date.now();
canvas.style.position = "absolute";
canvas.style.top = "0";
canvas.style.left = "0";
canvas.width = this.view.width;
canvas.height = this.view.height;
const context = canvas.getContext("2d");
this.context = context;
this.initWindy();
}initWindy(data) {this.windy = new Windy(
this.context.canvas,
this.layer.displayOptions,
undefined
);
}clear(stopDraw = true) {if (stopDraw) {this.stopDraw();
}if (this.context) {this.context.clearRect(0, 0, this.view.width, this.view.height);
}
}stopDraw() {this.windy.stop();
this.drawing = false;
}prepDraw(data) {if (data) this.windy.setData(data);this.setParticleDensity();
this.startDraw();
this.drawPrepping = false;
this.drawReady = true;
this.requestRender();
}startDraw() {// use the extent of the view, and not the extent passed into fetchImage...it was slightly off when it crossed IDL.
let extent = this.view.extent;
if (extent.spatialReference.isWebMercator) {extent = webMercatorUtils.webMercatorToGeographic(extent);
}this.northEast = new Point({x: extent.xmax, y: extent.ymax});
this.southWest = new Point({x: extent.xmin, y: extent.ymin});// resize the canvas
this.context.canvas.width = this.view.width;
this.context.canvas.height = this.view.height;// cater for the extent crossing the IDL
if (this.southWest.x > this.northEast.x && this.northEast.x < 0) {this.northEast.x = 360 + this.northEast.x;
}
}setParticleDensity() {if (!Array.isArray(this.layer.displayOptions.particleDensity)) {return; // not an array, so must be a number, exit out here as there's no calc to do
}const stops = this.layer.displayOptions.particleDensity;
const currentZoom = Math.round(this.view.zoom);
let density = -1;const zoomMap = stops.map((stop) => {return stop.zoom;
});
console.log("zoomMap", zoomMap);
// loop the zoomsfor (let i = 0; i < stops.length; i++) {const stop = stops[i];if (stop.zoom === currentZoom) {density = stop.density;
break;
}const nextStop = i + 1 < stops.length ? stops[i + 1] : undefined;
if (!nextStop) {// this is the last one, so just set to this value
density = stop.density;
break;
}if (nextStop.zoom > currentZoom) {density = stop.density;
break;
}
}// if density still not found, set it to the last value in the stops array
if (density === -1) {density = stops[stops.length - 1].density;
}this.windy.calculatedDensity = density;
}setDate() {if (this.windy) {if (this.windy.refTime && this.windy.forecastTime) {// assume the ref time is an iso string, or some other equivalent that javascript Date object can parse.
const d = new Date(this.windy.refTime);// add the forecast time as hours to the refTime;
d.setHours(d.getHours() + this.windy.forecastTime);
this.date = d;
return;
}
}this.date = undefined;
}
}var __extends = (this && this.__extends) || (function () {var extendStatics = function (d, b) {extendStatics = Object.setPrototypeOf ||
({__proto__: []} instanceof Array && function (d, b) {d.__proto__ = b;
}) ||
function (d, b) {for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
};
return extendStatics(d, b);
};
return function (d, b) {extendStatics(d, b);function __() {this.constructor = d;
}d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {var c = arguments.length,
r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {r = Reflect.decorate(decorators, target, key, desc);
} else {for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
}
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var AnimatedEnvironmentLayer = /** @class */ (function (_super) {__extends(AnimatedEnvironmentLayer, _super);function AnimatedEnvironmentLayer(properties) {var _this = _super.call(this, properties) || this;
// If the active view is set in properties, then set it here.
_this.url = properties.url;
_this.displayOptions = properties.displayOptions || {};
if (Array.isArray(_this.displayOptions.particleDensity)) {// make sure the particle density stops array is is order by zoom level lowest zooms first
_this.displayOptions.particleDensity.sort(function (a, b) {return a.zoom - b.zoom;
});
}
_this.reportValues = properties.reportValues === false ? false : true; // default to true
// watch url prop so a fetch of data and redraw will occur.
watchUtils.watch(_this, "url", function (a, b, c, d) {return _this._urlChanged(a, b, c, d);
});
// watch visible so a fetch of data and redraw will occur.
watchUtils.watch(_this, "visible", function (a, b, c, d) {return _this._visibleChanged(a, b, c, d);
});
// watch display options so to redraw when changed.
watchUtils.watch(_this, "displayOptions", function (a, b, c, d) {return _this._displayOptionsChanged(a, b, c, d);
});
_this.dataFetchRequired = true;
return _this;
}AnimatedEnvironmentLayer.prototype.createLayerView = function (view) {var _this = this;
// only supports 2d right now.
if (view.type !== "2d") {console.error("不支持3D(only supports 2d right now)", view.type)
return;
}
// hook up the AnimatedEnvironmentLayerView2D as the layer view
this.layerView = new AnimatedEnvironmentLayerView2D({view: view,
layer: this
});
this.layerView.view.on("pointer-move", function (evt) {return _this.viewPointerMove(evt);
});
this.draw(true);
return this.layerView;
};
AnimatedEnvironmentLayer.prototype.draw = function (forceDataRefetch) {var _this = this;
if (forceDataRefetch != null) {this.dataFetchRequired = forceDataRefetch;
}
if (!this.url || !this.visible) {return;
} // no url set, not visible or is currently drawing, exit here.
// if data should be fetched, go get it now.
if (this.dataFetchRequired) {this.isErrored = false;
this.dataLoading = true;
esriRequest(this.url, {responseType: "json"
})
.then(function (response) {_this.dataFetchRequired = false;
_this.doDraw(response.data); // all sorted draw now.
_this.dataLoading = false;
})
.otherwise(function (err) {console.error("Error occurred retrieving data. " + err);
_this.dataLoading = false;
_this.isErrored = true;
});
}
else {// no need for data, just draw. no need for data, just draw.
this.doDraw();
}
};
AnimatedEnvironmentLayer.prototype.stop = function () {if (this.layerView) {this.layerView.stopDraw();
}
};
AnimatedEnvironmentLayer.prototype.start = function () {this.doDraw();
};
AnimatedEnvironmentLayer.prototype.doDraw = function (data) {this.layerView.prepDraw(data);
};
AnimatedEnvironmentLayer.prototype.viewPointerMove = function (evt) {if (!this.layerView.windy || !this.visible) {return;
}
var mousePos = this._getMousePos(evt);
var point = this.layerView.view.toMap({x: mousePos.x, y: mousePos.y});
if (point.spatialReference.isWebMercator) {point = webMercatorUtils.webMercatorToGeographic(point);
}
var grid = this.layerView.windy.interpolate(point.x, point.y);
var result = {point: point,
target: this
};
if (!grid || (isNaN(grid[0]) || isNaN(grid[1]) || !grid[2])) {// the current point contains no data in the windy grid, so emit an object with no speed or direction object
//当前点在风网格中不包含任何数据,所以发射一个没有速度或方向的对象
this.emit("point-report", result);
return;
}
// get the speed and direction and emit the result 获得速度和方向,并发出结果
result.velocity = this._vectorToSpeed(grid[0], grid[1]);
result.degree = this._vectorToDegrees(grid[0], grid[1]);
this.emit("point-report", result);
};
AnimatedEnvironmentLayer.prototype._vectorToSpeed = function (uMs, vMs) {var speedAbs = Math.sqrt(Math.pow(uMs, 2) + Math.pow(vMs, 2));
return speedAbs;
};
AnimatedEnvironmentLayer.prototype._vectorToDegrees = function (uMs, vMs) {var abs = Math.sqrt(Math.pow(uMs, 2) + Math.pow(vMs, 2));
var direction = Math.atan2(uMs / abs, vMs / abs);
var directionToDegrees = direction * 180 / Math.PI + 180;
directionToDegrees += 180;
if (directionToDegrees >= 360) {directionToDegrees -= 360;
}
return directionToDegrees;
};
AnimatedEnvironmentLayer.prototype._getMousePos = function (evt) {// container on the view is actually a html element at this point, not a string as the typings suggest.
var container = this.layerView.view.container;
var rect = container.getBoundingClientRect();
return {x: evt.x - rect.left,
y: evt.y - rect.top
};
};
AnimatedEnvironmentLayer.prototype._urlChanged = function (a, b, c, d) {this.stop();
this.dataFetchRequired = true;
this.draw();
};
AnimatedEnvironmentLayer.prototype._visibleChanged = function (visible, b, c, d) {if (!visible) {this.stop();
}
else {this.draw();
}
};
AnimatedEnvironmentLayer.prototype._displayOptionsChanged = function (newOptions, b, c, d) {if (!this.layerView.windy) {return;
}
this.layerView.windy.stop();
this.layerView.windy.setDisplayOptions(newOptions);
this.draw();
};
__decorate([
asd.property(),
__metadata("design:type", String)
], AnimatedEnvironmentLayer.prototype, "url", void 0);
__decorate([
asd.property(),
__metadata("design:type", Object)
], AnimatedEnvironmentLayer.prototype, "displayOptions", void 0);
__decorate([
asd.property(),
__metadata("design:type", Boolean)
], AnimatedEnvironmentLayer.prototype, "reportValues", void 0);
__decorate([
asd.property(),
__metadata("design:type", Boolean)
], AnimatedEnvironmentLayer.prototype, "dataLoading", void 0);
__decorate([
asd.property(),
__metadata("design:type", Boolean)
], AnimatedEnvironmentLayer.prototype, "isErrored", void 0);
AnimatedEnvironmentLayer = __decorate([
asd.subclass("AnimatedEnvironmentLayer"),
__metadata("design:paramtypes", [Object])
], AnimatedEnvironmentLayer);
return AnimatedEnvironmentLayer;
}(asd.declared(GraphicsLayer)));
var Windy = /** @class */ (function () {function Windy(canvas, options, data) {this.NULL_WIND_VECTOR = [NaN, NaN, null]; // singleton for no wind in the form: [u, v, magnitude]
this.canvas = canvas;
this.setDisplayOptions(options);
this.gridData = data;
}Windy.prototype.setData = function (data) {this.gridData = data;
};
Windy.prototype.setDisplayOptions = function (options) {this.displayOptions = options;
// setup some defaults
this.displayOptions.minVelocity = this.displayOptions.minVelocity || 0;
this.displayOptions.maxVelocity = this.displayOptions.maxVelocity || 10;
this.displayOptions.particleDensity = this.displayOptions.particleDensity || 10;
this.calculatedDensity = Array.isArray(this.displayOptions.particleDensity) ? 10 : this.displayOptions.particleDensity;
this.displayOptions.velocityScale = (this.displayOptions.velocityScale || 0.005) * (Math.pow(window.devicePixelRatio, 1 / 3) || 1); // scale for velocity (completely arbitrary -- this value looks nice)
this.displayOptions.particleAge = this.displayOptions.particleAge || 90;
this.displayOptions.lineWidth = this.displayOptions.lineWidth || 1;
this.displayOptions.particleReduction = this.displayOptions.particleReduction || (Math.pow(window.devicePixelRatio, 1 / 3) || 1.6); // multiply particle count for mobiles by this amount
this.displayOptions.frameRate = this.displayOptions.frameRate || 15;
var defaultColorScale = ["rgb(61,160,247)", "rgb(99,164,217)", "rgb(138,168,188)", "rgb(177,173,158)", "rgb(216,177,129)", "rgb(255,182,100)", "rgb(240,145,87)", "rgb(225,109,74)", "rgb(210,72,61)", "rgb(195,36,48)", "rgb(180,0,35)"];
this.colorScale = this.displayOptions.colorScale || defaultColorScale;
this.FRAME_TIME = 1000 / this.displayOptions.frameRate; // desired frames per second
};
Windy.prototype.start = function (bounds, width, height, extent) {var _this = this;
var mapBounds = {south: this.deg2rad(extent[0][1]),
north: this.deg2rad(extent[1][1]),
east: this.deg2rad(extent[1][0]),
west: this.deg2rad(extent[0][0]),
width: width,
height: height
};
this.stop();
// build grid
this.buildGrid(this.gridData, function (gridResult) {var builtBounds = _this.buildBounds(bounds, width, height);
_this.interpolateField(gridResult, builtBounds, mapBounds, function (bounds, field) {// animate the canvas with random points
Windy.field = field;
_this.animate(bounds, Windy.field);
});
});
};
Windy.prototype.stop = function () {if (Windy.field) {Windy.field.release();
}
if (Windy.animationLoop) {cancelAnimationFrame(Windy.animationLoop);
}
};
/**
* Get interpolated grid value from Lon/Lat position
* @param lon {Float} Longitude更多消息参考https://xiaozhuanlan.com/topic/2178340659

arcgis js 4 风场可视化相关推荐

  1. 基于ArcGIS JS API 4.11实现对FeatureLayer的多变量渲染

    文章目录 需求背景 需求分析 开发过程 效果图 注意事项 参考链接 在线示例 需求背景 有一个二维数组,里面包含几万个表示高度的值,现在要把这些高度值在地图上展示出来.可以通过小立方体的方式展现,长宽 ...

  2. 08 ArcGIS JS API 4.15实现萤火虫效果

    概述 前几天在看帖子的时候发现有大佬使用ArcGIS Pro和Portal制作了萤火虫的渲染效果,感觉前端可视化的时候还不错,所以自己也将实例数据下载下来之后用ArcGIS JS API来实现了一下, ...

  3. 基于three.js 和ArcGIS JS API 建筑物立面动态特效渲染

    基于three.js 和ArcGIS JS API 建筑物立面波纹墙动态渲染 简介 基于ArcGIS JS API 和 three.js 波纹墙扩展类ripplewallRenderer 波纹墙扩展类 ...

  4. ArcGIS JS 学习笔记4 实现地图联动

    原文:ArcGIS JS 学习笔记4 实现地图联动 1.开篇 守望屁股实在太好玩了,所以最近有点懒,这次就先写个简单的来凑一下数.这次我的模仿目标是天地图的地图联动. 天地的地图联动不仅地图有联动,而 ...

  5. ArcGIS JS API 4.X实现动态地图服务子图层显隐控制

    ArcGIS JS API 4.X实现动态地图服务子图层显隐控制 文章目录 ArcGIS JS API 4.X实现动态地图服务子图层显隐控制 使用场景 官网示例 注意事项 使用场景 图层控制功能 官网 ...

  6. ArcGIS JS API加载GeoServer发布的WFS服务

    文章目录 前言 主要代码 总结 参考链接 前言 WFS(Web Feature Service),OGC标准下的要素服务.其支持的主要操作如下: GetCapabilities (discovery ...

  7. 使用ArcGIS JS API加载WMTS图层的两种方式

    文章目录 前言 方式一 方式二 前言 某些项目可能多方参与,每一方使用的GIS平台有时会有所不同,这时为了统一各方地图服务,通常会发布OGC标准的WMTS地图服务供各方使用.ArcGIS API fo ...

  8. 基于ArcGIS JS API实现垂直滑动缩放条

    文章目录 需求背景 需求分析 效果图 完整代码 注意事项 严格来说并不是基于ArcGIS JS API,应该是基于Dojo的dijit里面的VerticalSlider和VerticalRule,但是 ...

  9. 基于ArcGIS JS API封装dojo微件(以工具条为例)

    1.应用场景: 我们知道ArcGIS JS API自带了一些微件(或者说是控件),比如缩放按钮.定位按钮等等.但是有的时候这些微件的样式不太符合项目实际要求,或者是项目上想要把这些组合起来,这时候我们 ...

最新文章

  1. awt简单应用 panel面板
  2. 深度学习(DL)与卷积神经网络(CNN)学习笔记随笔-03-基于Python的LeNet之LR
  3. Response_案例2_输出字符数据
  4. 避免使用CreateThread函数,导致的内存泄露
  5. 如何解开机器学习的面纱?
  6. ORA-28009:connection as SYS should be as SYSDBA OR SYSOPER
  7. 根据周次显示日期范围_Elasticsearch根据日期价格范围搜索酒店且排序
  8. github private链接访问_Hands-On Design Patterns With C++(十八)访问者模式与多分派(下)...
  9. 无法定位序数XX于动态链接库XX.dll的解决的方法
  10. python指南针_用形状文件或地质指南针绘制遮住的南极洲
  11. 大数据存储1----什么是hdfs!!!
  12. Networkx如何画点图并显示边权
  13. OpenGL环境下PLY三维模型的读入与显示
  14. easyrecovery2023最新版本电脑数据恢复软件特点介绍
  15. 前端的岗位以及初步了解
  16. MySQL多表查询练习题
  17. Leetcode-892. 三维形体的表面积
  18. 扫码枪多次扫码用空格分开
  19. 【L2-019 悄悄关注 】天梯赛L2系列详解
  20. 如何配置一部4块Titan X GPU的深度学习机器

热门文章

  1. docker容器 如何精简镜像减小体积
  2. 【CFD理论】对流项-02
  3. 使用moment获取当天日期与下一天
  4. 基于Hashids的高效游戏礼包兑换码系统完整设计
  5. MySQL第十次作业
  6. Flash 的fla文件读写 可以直接更改图片路径
  7. 苹果系统设置http代理ip教程
  8. 基于宜搭的《T恤尺码收集》应用搭建最佳实践
  9. 基于主轴变换的医学图像倾斜校正
  10. Android事件总线——EventBus的使用