用ArcGIS API for JavaScript制作三维可视化图
前段时间接了一个项目,涉及到了空间信息三维可视化的工作。之前在网上查找无意中看到ArcGIS API for JavaScript(以下简称“ArcGIS API”或“该API”)可以在网页上制作三维可视化图。好在有友人在国外帮我把整个文档和API下载下来了,于是就着手学习了一下这个API。
简介
做GIS的肯定清楚ArcGIS是什么,包括一系列的ArcMap、ArcScence、ArcEngine等。ArcGIS推出了这套JavaScript API,现在有4.2版本,该版本可以创建二维、三维的网页应用程序。
下面是官网给出的一些三维可视化的示例。
ArcGIS制作可视化图的大体结构为:View 包含 Map 包含 Layer(s) 包含 Graphic(s)。带(s)表示是一个数组。其中
- View(视图):对应HTML上的一个元素,在该元素中显示底图以及底图上的所有图层。
- Map(底图):可以为多种类型:街道图、卫星图、大洋图、地表图等。
- Layer(图层):有多种类型,如FeatureLayer、GraphicLayer、PointCloudLayer,甚至有CSVLayer等。对于图层的解释,ArcGIS官方文档指出:
图层是 ArcMap、ArcGlobe 和 ArcScene 中地理数据集的显示机制。一个图层引用一个数据集,并指定如何利用符号和文本标注绘制该数据集。向地图添加图层时,要指定它的引用数据集并设定地图符号和标注属性。
- Graphic(图形):图形在官方文档中的解释是:“图形是一个矢量图,代表了真实世界的地理事物或地理现象。它可以包含geometry(几何)、symbol(符号)、attributes(特性)。”
A Graphic is a vector representation of real world geographic phenomena. It can contain geometry, a symbol, and attributes.A Graphic is displayed in the GraphicsLayer.
当我们拿到带有空间信息的数据,就可以对每个数据设计可视化的图形,将同类的数据显示的图形添加到同一个图层中,就可以显示了。官方指出Graphic是显示在GraphicLayer中的,但是FeatureLayer中有一个source属性,可以将Grapchic自动转换(autocast),从而在Layer中显示。
制作可视化图
使用ArcGIS API,需要引用各个组件(Map, SenceView, FeatureLayer ...),各个组件引用的路径在官网文档上会标注。引用时使用require()函数(这里使用TypeScript语法表示变量的类型)
require(modules: Array<String>, callback: function) => void
即可将各个组件引用到应用程序中。其中
- modules:是一个字符串数组,每一项代表了一个组件的引用路径。例如,组件Map的地址是 “esri/Map” 。
- callback:是一个回调函数,表示各个组件加载完成后执行的函数操作。这个函数的的参数比较特别,参数个数与modules中引用的组件的个数相同,每个参数与modules中的组件路径一一对应,表示引用的各个组件的一个对象。
于是,脚本整体上类似于:
require(["esri/Map","esri/views/SceneView","dojo/domReady!" ], function(Map, SceneView) {// Code to create the map and view will go here });
当然这些脚本要写在一对script标签里。
添加底图
在ArcGIS API中,所有地图要素都是以对象的形式存在的。要在地图上添加地理地图,就需要创建地理地图对象。Map类的对象就表示一个地理地图。当引用了MA类组件之后,就可以创建其一个Map类的对象了。
var map = new Map({basemap: "streets",ground: "world-elevation" });
Map类的属性有这些:
- basemap:地理底图的类型。ArcGIS提供了多种类型的地理底图,包括了OpenStreetMap(osm)。
- layers:包含了地图上展示的要素所在的图层,这个图层是“可操作的”,包括FeatureLayers、WebTileLayers和GraphicsLayers,其中不包含basemaps,也就是无法通过访问layers属性访问basemap。
- allLayers:与layers属性不同的是,这个属性包含了basemap图层、ground图层以及“可操作图层”。
- ground:这个属性只在使用三维视角的时候有用。ground属性是一个Ground类的对象,它将真实世界的地形或地势渲染到底图上。它包含了一组图层来显示地图。在创建地理底图的时候,ground属性可以包含一组layer,也可以仅仅赋予一个字符串 world-elevation ,通过操作ground中的layer属性来对底图进行操作。示例见Toggle ground elevation。
通过调节这些属性,就可以实现我们想要的地图。
添加视图
我们需要一个视图来对我们所制作的地图进行观察,包括对底图的观察以及其他所有要素的观察。在ArcGIS软件中,如果制作二维地图或进行二维分析,就使用ArcMap软件;如果制作三维地图或进行三维分析,就使用ArcScene软件。在ArcGIS API中也是一样的。我们如果制作二维地图,就使用MapView类的对象创建视图;如果制作三维地图,就使用SceneView类的对象创建视图。
创建一个视图可以的方法与创建底图类似,如
var view = new SceneView({container: "viewDiv",map: map });
这个SceneView的属性非常多,日后有空一一列举,与我们制作的三维地图关系较大的有:
- container:是一个DOM元素的id,地图将渲染在该DOM元素内。ArcGIS API制作的地图可以自适应。
- map:显示的底图。制作好底图后,在这里引用制作的底图实例,即可在地图上显示。
- camera:视图摄像机。摄像机代表了三位观察的位置和方向。该属性是一个Camera类的实例,使用三个参数确定了摄像机的位置和方向:
- position:摄像机的位置。是一个Point类的对象,可以使用经(longitude)纬(latitude)度作为平面位置的参数,也可以使用大地坐标(x, y)作为平面位置的参数。高程都是用z属性来指定的。还有一个spatialReference的属性,用于指定参考系。
- heading:摄像机朝向的方位角。
- tilt:摄像机的“垂直角”,这个定义与测量学中的垂直角(天顶距)定义不同,当摄像机竖直向下时,该角度为0°。
一旦创建了视图对象,就会在选定的DOM元素中进行渲染。
添加图层
ArcGIS API提供了丰富的图层可以使用,但是不同的图层代表了不同的含义。这里只分析一下FeatureLayer和GraphicLayer的区别:当图层与某一地理实体相对应时,最好使用FeatureLayer,表示是地理要素的图层,具有实体含义;否则使用GraphicLayer,表示仅仅是一些几何元素,没有地理含义。
我所拿到的项目要可视化的内容具有地理实体含义,所以使用FeatureLayer。一个FeatureLayer对象包含很多属性,可以通过REST服务创建,也可以本地创建。使用REST服务创建需要发布REST服务,然后在url属性上填入REST服务的地址。这里介绍从本地创建FeatureLayer中的要素,官网示例见Sample - Create a FeatureLayer with GeoJSON data。
如果要从本地创建要素,需要同时设置FeatureLayer的五个属性:fields、objectIdField、spatialReference、geometryType和source。
- fields:是一个对象数组,相当于ArcMap中的属性表各个字段的配置,每一个对象表示了属性表中的一个字段。每个对象有以下几个常用属性
- name:字段名。
- type:字段的数据类型,与ArcMap中一样,有small-integer、integer、single、double、string、date、oid、geometry、blob、raster、guid、global-id、xml等。
- alias:字段替用名。
- length:字段长度。
- nullable:字段是否可空。
- editable:字段时候可编辑。
- objectIdField:指定fields中那个字段代表了要素的ObjectId。ObjectId是每个要素的唯一标识符。
- spatialReference:指定地理参考系。
- geometryType:表示要素的几何类型,有point、mulitpoint、polyline、polygon等类型。
- source:是一个Graphic对象的集合。每个Graphic对象包括三个部分:geometry、symbol和attribute。
- geometry:是一个Geometry类的对象,定义了Graphic对象的地理位置。Geometry类的派生类有Point(点)、MultiPoint(多点)、Polyline(折线)、Polygon(折线)等。
- symbol:该要素显示时的符号,代表了可视化方式。在创建Graphic对象的时候直接指定其symbol属性不是一个比较好的做法。比较好的做法是使用Renderer(渲染器)来对图层中的所有要素进行统一渲染。
- attribute:是一个对象数组,每个对象要包含fields中声明的所有不可空字段。
除此之外,还有一些属性是非常有用的:
- renderer:渲染器。是一个Renderer类的对象,表示对要素的geometry和attribute如何进行渲染。
- popupTemplate:弹出框的模板,是一个PopupTemplate对象,可以用来显示要素的数据。
当我们获取到了可视化的数据,首先创建一个Graphic数组,在官网示例中,是这样的
return arrayUtils.map(geoJson.features, function(feature, i) {return {geometry: new Point({x: feature.geometry.coordinates[0],y: feature.geometry.coordinates[1]}),// select only the attributes you care about attributes: {ObjectID: i,title: feature.properties.title,type: feature.properties.type,place: feature.properties.place,depth: feature.geometry.coordinates[2] + " km",time: feature.properties.time,mag: feature.properties.mag,mmi: feature.properties.mmi,felt: feature.properties.felt,sig: feature.properties.sig,url: feature.properties.url}}; });
这里使用了arrayUtils的方法将一个数组映射为另一个数组。也可以使用foreach循环来完成这件事。将Griphic数组用一个变量保存起来。
fields也需要我们进行创建,官网的示例中创建了如下的属性表:
var fields = [{name: "ObjectID",alias: "ObjectID",type: "oid"},{name: "title",alias: "title",type: "string"},{name: "type",alias: "type",type: "string"},{name: "place",alias: "place",type: "string"},{name: "depth",alias: "depth",type: "string"},{name: "time",alias: "time",type: "date"},{name: "mag",alias: "Magnitude",type: "double"},{name: "url",alias: "url",type: "string"},{name: "mmi",alias: "intensity",type: "double"},{name: "felt",alias: "Number of felt reports",type: "double"},{name: "sig",alias: "significance",type: "double"} ];
我们现在就可以创建FeatureLayer了,示例代码如下:
var lyr = new FeatureLayer({source: graphics, // autocast as an array of esri/Graphic// create an instance of esri/layers/support/Field for each field objectfields: fields, // This is required when creating a layer from GraphicsobjectIdField: "ObjectID", // This must be defined when creating a layer from Graphicsrenderer: quakesRenderer, // set the visualization on the layer spatialReference: {wkid: 4326},geometryType: "point", // Must be set when creating a layer from Graphics popupTemplate: pTemplate });map.add(lyr);
最后一行通过map类对象的add()方法,将该要素图层添加到地图上。其中,quakesRenderer是创建的渲染器,下小节中会详细讲解。
设计渲染器
渲染器是地图显示符号的方法,相当于Echarts中的VisualMap配置项。ArcGIS API中有很多渲染器,我们这里对点符号的渲染可以使用SimpleRenderer,有几个属性
- label:渲染器标签。
- symbol:渲染用的符号。是Symbol类的一个对象。Symbol的派生类包含了丰富的可视化类型,有二维的和三维的。如果使用三维的可视化符号,使用Symbol3D类,包括二维可视化符号的三维版本和一些三维可视化特有的符号,如MeshSymbol3D。
- visualVariables:视觉变量,是一个对象数组。效果类似于Echarts中的VisualMap配置项,可以根据某一属性值对颜色、尺寸、透明度、旋转角度进行映射调整。每一个元素都是以下几种类型:ColorVisualVariable、SizeVisualVariable、OpacityVisualVariable、RotationVisualVariable。
官网设计的渲染器如下所示:
var quakesRenderer = new SimpleRenderer({ symbol: new SimpleMarkerSymbol({style: "circle",size: 20,color: [211, 255, 0, 0],outline: {width: 1,color: "#FF0055",style: "solid"} }), visualVariables: [ {type: "size",field: "mag", // earthquake magnitudevalueUnit: "unknown",minDataValue: 2,maxDataValue: 7,// Define size of mag 2 quakes based on scale minSize: {type: "size",expression: "view.scale",stops: [{value: 1128,size: 12},{value: 36111,size: 12},{value: 9244649,size: 6},{value: 73957191,size: 4},{value: 591657528,size: 2}]},// Define size of mag 7 quakes based on scale maxSize: {type: "size",expression: "view.scale",stops: [{value: 1128,size: 80},{value: 36111,size: 60},{value: 9244649,size: 50},{value: 73957191,size: 50},{value: 591657528,size: 25}]} }] });
这个渲染器的效果如下所示
整体代码
1 var arcgis_groupLayer; 2 3 function ArcGIS_Map_Init() { 4 require([ 5 "esri/layers/GroupLayer", 6 "esri/layers/FeatureLayer", 7 "esri/Map", 8 "esri/views/SceneView", 9 "esri/widgets/LayerList", 10 "esri/layers/support/Field", 11 "esri/geometry/Point", 12 "esri/renderers/SimpleRenderer", 13 "esri/symbols/PointSymbol3D", 14 "esri/symbols/ObjectSymbol3DLayer", 15 "esri/request", 16 "dojo/_base/array", 17 "dojo/dom", 18 "dojo/on", 19 "dojo/domReady!" 20 ], function (GroupLayer, FeatureLayer, Map, SceneView, LayerList, Field, Point, SimpleRenderer, PointSymbol3D, ObjectSymbol3DLayer, esriRequest, 21 arrayUtils, dom, on) { 22 23 var arcgis_fields = [ 24 {name: "ObjectID", alias: "ObjectID", type: "oid"}, 25 {name: "title", alias: "title", type: "string"}, 26 {name: "num", alias: "num", type: "integer"} 27 ]; 28 29 arcgis_groupLayer = new GroupLayer({ 30 title: "消防数据", 31 visibility: true, 32 visibilityMode: "exclusive" 33 }) 34 35 var arcgis_arcgismap = new Map({ 36 basemap: "osm", 37 layers: [arcgis_groupLayer] 38 }); 39 40 var arcgis_initCam = { 41 position: { 42 x: 120.61, 43 y: 30.50, 44 z: 100000, 45 spatialReference: { 46 wkid: 4326 47 } 48 }, 49 heading: 15, 50 tilt: 60 51 }; 52 53 var arcgis_view = new SceneView({ 54 map: arcgis_arcgismap, 55 container: "arcgismap", 56 camera: arcgis_initCam 57 }); 58 59 arcgis_view.then(function () { 60 arcgis_layerList = new LayerList({ 61 view: arcgis_view 62 }) 63 64 arcgis_view.ui.add(arcgis_layerList, "top-right"); 65 }) 66 67 $.getJSON("js/json/fire.json", function (data) { 68 var graphics = []; 69 70 data.forEach(function(iSender, i) { 71 graphics.push({ 72 geometry: new Point({ 73 longitude: iSender.longitude, 74 latitude: iSender.latitude 75 }), 76 attributes: { 77 ObjectID: iSender.senderId, 78 title: iSender.senderName, 79 num: iSender.num 80 } 81 }) 82 }, this); 83 84 var arcgis_fireRenderer = new SimpleRenderer({ 85 symbol: new PointSymbol3D({ 86 symbolLayers: [new ObjectSymbol3DLayer({ 87 resource: { 88 primitive: "cube" 89 }, 90 width: 500, 91 depth: 500, 92 material: {color: "#e6b600"} 93 })] 94 }), 95 label: "火警数", 96 visualVariables: [{ 97 type: "size", 98 field: "num", 99 axis: "height" 100 },{ 101 type: "size", 102 axis: "width-and-depth", 103 useSymbolValue: true, 104 }] 105 }); 106 107 var arcgis_fireLayer = new FeatureLayer({ 108 source: graphics, 109 fields: arcgis_fields, 110 objectIdField: "ObjectID", 111 renderer: arcgis_fireRenderer, 112 spatialReference: { 113 wkid: 4326 114 }, 115 geometryType: "point", 116 popupTemplate: { 117 title: "{title}", 118 content: [{ 119 type: "fields", 120 fieldInfos: [{ 121 fieldName: "num", 122 label: "火警数", 123 visible: true 124 }] 125 }] 126 }, 127 title: "火警数", 128 id: "fireLayer" 129 }) 130 131 arcgis_groupLayer.add(arcgis_fireLayer, 0); 132 }) 133 134 $.getJSON("js/json/fault.json", function (data) { 135 var graphics = []; 136 137 data.forEach(function(iSender, i) { 138 graphics.push({ 139 geometry: new Point({ 140 longitude: iSender.longitude, 141 latitude: iSender.latitude 142 }), 143 attributes: { 144 ObjectID: iSender.senderId, 145 title: iSender.senderName, 146 num: iSender.num 147 } 148 }) 149 }, this); 150 151 var arcgis_faultRenderer = new SimpleRenderer({ 152 symbol: new PointSymbol3D({ 153 symbolLayers: [new ObjectSymbol3DLayer({ 154 resource: { 155 primitive: "cube" 156 }, 157 width: 500, 158 depth: 500, 159 material: {color: "#0098d9"} 160 })] 161 }), 162 label: "故障数", 163 visualVariables: [{ 164 type: "size", 165 field: "num", 166 axis: "height" 167 },{ 168 type: "size", 169 axis: "width-and-depth", 170 useSymbolValue: true, 171 }] 172 }); 173 174 var arcgis_faultLayer = new FeatureLayer({ 175 source: graphics, 176 fields: arcgis_fields, 177 objectIdField: "ObjectID", 178 renderer: arcgis_faultRenderer, 179 spatialReference: { 180 wkid: 4326 181 }, 182 geometryType: "point", 183 popupTemplate: { 184 title: "{title}", 185 content: [{ 186 type: "fields", 187 fieldInfos: [{ 188 fieldName: "num", 189 label: "故障数", 190 visible: true 191 }] 192 }] 193 }, 194 title: "故障数", 195 id: "faultLayer", 196 visible: false 197 }) 198 199 arcgis_groupLayer.add(arcgis_faultLayer, 1); 200 }) 201 202 $.getJSON("js/json/linkage.json", function (data) { 203 var graphics = []; 204 205 data.forEach(function(iSender, i) { 206 graphics.push({ 207 geometry: new Point({ 208 longitude: iSender.longitude, 209 latitude: iSender.latitude 210 }), 211 attributes: { 212 ObjectID: iSender.senderId, 213 title: iSender.senderName, 214 num: iSender.num 215 } 216 }) 217 }, this); 218 219 var arcgis_linkageRenderer = new SimpleRenderer({ 220 symbol: new PointSymbol3D({ 221 symbolLayers: [new ObjectSymbol3DLayer({ 222 resource: { 223 primitive: "cube" 224 }, 225 width: 500, 226 depth: 500, 227 material: {color: "#2b821d"} 228 })] 229 }), 230 label: "联动数", 231 visualVariables: [{ 232 type: "size", 233 field: "num", 234 axis: "height" 235 },{ 236 type: "size", 237 axis: "width-and-depth", 238 useSymbolValue: true, 239 }] 240 }); 241 242 var arcgis_linkageLayer = new FeatureLayer({ 243 source: graphics, 244 fields: arcgis_fields, 245 objectIdField: "ObjectID", 246 renderer: arcgis_linkageRenderer, 247 spatialReference: { 248 wkid: 4326 249 }, 250 geometryType: "point", 251 popupTemplate: { 252 title: "{title}", 253 content: [{ 254 type: "fields", 255 fieldInfos: [{ 256 fieldName: "num", 257 label: "联动数", 258 visible: true 259 }] 260 }] 261 }, 262 title: "联动数", 263 id: "linkageLayer", 264 visible: false 265 }) 266 267 arcgis_groupLayer.add(arcgis_linkageLayer, 2); 268 }) 269 }) 270 } 271 272 spatial_echarts_instant.arcgismap = { 273 init: function () { 274 ArcGIS_Map_Init(); 275 }, 276 clear: function (params) { 277 arcgis_view = {}; 278 }, 279 resize: function (params) { 280 281 }, 282 setOption: function (params) { 283 require([ 284 "esri/views/SceneView" 285 ], function (SceneView) { 286 arcgis_view = new SceneView({ 287 map: arcgis_arcgismap, 288 container: "arcgismap", 289 camera: arcgis_initCam 290 }); 291 }) 292 }, 293 changeLayer: function (layerIndex) { 294 var layerId = null; 295 switch (layerIndex) { 296 case 1: 297 layerId = "fireLayer"; 298 break; 299 case 2: 300 layerId = "faultLayer"; 301 break; 302 case 3: 303 layerId = "linkageLayer"; 304 break; 305 default: 306 break; 307 } 308 if (layerId) { 309 var layer = arcgis_groupLayer.findLayerById(layerId); 310 layer.visible = true; 311 } 312 } 313 } 314 315 $(function () { 316 ArcGIS_Map_Init(); 317 })
转载于:https://www.cnblogs.com/MSspblxh/p/6273998.html
用ArcGIS API for JavaScript制作三维可视化图相关推荐
- ArcGIS API for JavaScript之基础篇(二)
ArcGIS API for JavaScript之基础篇(二) 上一篇文章介绍了Map MapView SceneView的基本知识以及简单的demo.最近几天学习了WebMap WebScene ...
- ArcGIS API for JavaScript——地图展示
ArcGIS API for JavaScript 能够实现的最基本功能就是地图展示,包括地图缩放.平移.定位.实时显示坐标.展示地图要素(指北针.比例尺.图例).切换地图等.本文将详细介绍地图展示的 ...
- 视频教程-主流前端框架下ArcGIS API for JavaScript的开发-其他
主流前端框架下ArcGIS API for JavaScript的开发 毕业于中国矿业大学地理信息科学专业.现就任于全球领先的GIS公司,主要担任地理平台研发工作,日常工作任务是ArcGIS JS A ...
- ArcGIS API for JavaScript web前端应用
ArcGIS API for JavaScript 文档查看地址: https://developers.arcgis.com/javascript/latest/ 现在分未3.x和4.x两种版本,对 ...
- 13 ArcGIS API for JavaScript开发入门文档
写在前面 这篇文章写在我用ArcGIS API for JavaScript(后面统称为"ArcGIS JS API")开发了两年项目后的某一天夜里.写这篇文章主要是两个目的吧,第 ...
- arcgis api for JavaScript _跨域请求
arcgis api for JavaScript 中出现跨域请求是常见问题, 通常出现类似如下错误消息类似: XMLHttpRequest cannot load http://10.32.2.7 ...
- 基于ArcGIS API for JavaScript加载天地图
文章目录 前言 效果图 详细代码 总结 参考链接 前言 该篇主要介绍如何用ArcGIS JS API加载天地图,具体应用场景以及需求分析等,在上篇基于ArcGIS API for JavaScript ...
- 基于ArcGIS API for JavaScript加载百度各种类型切片地图
文章目录 应用场景 需求分析 效果图 实现代码 原理解读 应用场景 部分项目基于ArcGIS平台,但是甲方只提供部分矢量数据,用作底图的地形图数据没有,表示可以使用百度地图作为底图.所以才会有使用Ar ...
- ArcGIS.Server.9.3和ArcGIS API for JavaScript实现Identify功能(六)
目的: 1.ArcGIS.Server.9.3和ArcGIS API for JavaScript实现Identify功能,鼠标点击后获取被点击对象的然后以infoWindow的方式显示点击对象的属性 ...
最新文章
- 第七章 右左法则----复杂指针解析
- 机器学习知识点(二十八)Beta分布和Dirichlet分布理解
- java复制类mytool_MyTools
- 时序分析:Kalman滤波(状态空间)
- Swift - 数组排序方法(附样例)
- python列表添加字符串_2.python基础之—列表,元组,字典,集合,字符串的使用方法...
- 一文详解Serverless架构模式
- iPad开发(相对于iPhone开发时专有的API)
- 软件单元测试数据分析模板,单元测试报告模板
- 高清录播系统与流媒体服务器,来同品牌全高清录播系统方案
- 计算机术语 gc 是什么意思,GC是什么?为什么我们要去使用它
- URAL-1941	 Scary Martian Word 队列维护
- 【codeforces round#800 B. Paranoid String】DP
- esp32-qcloud腾通连连编译指南
- 苹果免密支付怎么关闭_有人苹果手机被盗刷了!那是设置有问题...
- [组图教程]:8大方法!解决CPU资源占用100%[ZT]
- 微信小程序怎么样与mysql一起开发_莲米粒是一个基于PHP+MySQL+微信小程序技术栈...
- Karplus-Strong Algorithm 弦乐器模拟 吉他弦乐器发声原理 泛音 乐理概述
- 前端开发免费学习资源分享
- 从零开始建站(四) - 后端项目搭建
热门文章
- Springboot 分布式会话 io.lettuce.core.RedisCommandExecutionException: NOAUTH Authentication required
- Qlik Sense的8个提示和技巧
- JS学习笔记——前端的webview是什么东西
- Moviepy模块之视频添加字幕(一)
- Linux - Tcpdump工具
- linux 常用命令搜集 —— 筑梦之路
- 影像科dsa为什么必须买维修保险_浅谈DSA基本部件的维修技巧
- 【财富空间】达利欧:一切解读都不及自己用16页ppt彻底讲清
- 除了Visio还有哪个软件画流程图好用呢?
- 一文讲述,什么是pci总线原理?