ArcGIS API for JavaScript应用开发

原创
2019/01/25 06:55
阅读数 25
ArcGIS API for JavaScript 应用开发简介



一、开发环境准备

     ArcGIS API for JavaScript 提供在线版API,4.x 是 ArcGIS API for JavaScript 的新一代版本,实现了2D和3D应用的完全集成,3.x是一个2D版本,编程思路差异还是比较大的。开发调试过程中,最好进行本地化部署。ArcGIS JavaScript API可以从Esri官网获取,需要先注册一个Esri全球账户。SDK本地化部署指在本地Web Server上的部署,在API文件夹arcgis_js_api\library\3.18\install_win.html中有官方的部署文档,基本过程如下:

  • 复制 \arcgis_js_api\library 所有文件夹到你的Web server上,例如:复制到默认网站C:\Inetpub\wwwroot\arcgis_js_api\library下,

  • 本地化配置,打开C:\Inetpub\wwwroot\arcgis_js_api\library\3.16\3.16\init.js 查找 [HOSTNAME_AND_PATH_TO_JSAPI],替换为 本地server路径" <myserver>/arcgis_js_api/library/3.18/3.18/ ",如" 127.0.0.1/arcgis_js_api/library/3.18/3.18 "。打开C:\Inetpub\wwwroot\arcgis_js_api\library\3.18\3.18\dojo\dojo.js 查找[HOSTNAME_AND_PATH_TO_JSAPI],替换为 "<myserver>/arcgis_js_api/library/3.18/3.18/"例如"127.0.0.1/arcgis_js_api/library/3.18/3.18"

脚本中使用本地化SDK时(版本以3.16为例),嵌入如下语句。

    ...

<link rel="stylesheet" href="http://127.0.0.1/arcgis_js_api/library/3.16/3.16/dijit/themes/claro/claro.css"/>

<link rel="stylesheet" type="text/css" href="http://127.0.0.1/arcgis_js_api/library/3.16/3.16/esri/css/esri.css" />

<script type= "text/javascript" src= "http://127.0.0.1/arcgis_js_api/library/3.16/3.16/init.js" ></script>

    ...

使用在线API时 ,即所谓Content Delivery Network (CDN),对应要素替换为:

     <link rel="stylesheet" href="https://js.arcgis.com/3.18/dijit/themes/claro/claro.css"/>

     <link rel="stylesheet" type="text/css" href="https://js.arcgis.com/3.18/esri/css/esri.css" />

     https://js.arcgis.com/3.18


二、打开地图

      一个最基本的打开地图的应用脚本,使用由ERSI提供的缺省数据,以及CDN的API(在线API):

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

    <title>第一个地图应用</title>

    <link rel="stylesheet" href="https://js.arcgis.com/3.18/dijit/themes/claro/claro.css"/>

    <link rel="stylesheet" type="text/css" href="https://js.arcgis.com/3.18/esri/css/esri.css" />

    <style>

           html, body ,#map{ height: 100%; width: 100%; margin: 0; padding: 0; }

    </style>

<script type="text/javascript" src="https://js.arcgis.com/3.18" ></script>

<script>

  //Dojo模块,使用在线缺省数据。

        require(["esri/map", "dojo/domReady!"], function (Map) {

            //初始化<div id="map" ></div>的map容器

            var map = new Map("map", {

                center: [-118, 34.5],

                zoom: 8,

                basemap: "topo"

            });

        });

     </script>

</head>

<body>

      <div id="map" >

      </div>

  </body>

</html>


脚本运行效果如图所示:


打开地图的核心代码是:

       ....

var map = new Map("map", {

                center: [-118, 34.5],

                zoom: 8,

                basemap: "topo"

            });

       ....

这段代码相当于创建了一个地图容器,定位在center处,显示在第8级。3.18的Map对象可以认为是一个view+doc的对象,在4.0后,就将Map和View分开了,一个负责数据管理,一个负责显示及控制。ESRI在网上为basemap提供的缺省选项包括”topo”,"satellite", "hybrid", "topo", "gray", "oceans", "osm", "national-geographic"等几类。去掉basemap就是打开一个白图。

如从打开一个空白地图开始,逐个打开图层并加入地图,就可以完成地图的调用了,类似如下代码:

...

var map,tiled_layers;

//创建map

map = new Map("map", {

          center: [-96.541, 38.351],

          zoom: 14,

         slider: false

 });

//根据图层服务的URL地址,或图层文件的URL地址打开图层

tiled_layers= new ArcGISTiledMapServiceLayer("图层服务所在的URL",{打开选项,可全用缺省});

//加入地图

    map.addLayer(tiled_layers);

    ...

     当然,前提是这些图层的都是预先配准好的,显示风格也有了较好的缺省设置,否则的话,就得对他们的显示属性进行设置。常用的的图层对象主要有以下几种:

...

GraphicsLayer,一般矢量地图,一般用来处理业务数据;

FeatureLayer,矢量地图,由Arcgis维护的矢量地图数据

ArcGISTiledMapServiceLayer 经过切片缓冲过的地图,背景地图一般用这种方式;

ArcGISDynamicMapLayer, 从mdx文档发布出来的矢量图

MapImageLayer,经地理编码的影像,可与地图一块叠加;

WMSLayer, 符合OGC Web Map Services (WMS)的服务提供的Map图层. ;

WFSLayer ,符合 OGC Web Feature Services (WFS)要求的服务提供的矢量图层. ;

CSVLayer,利用服务器上的CSV file (.csv, .txt)产生的图层。

KMLLayer,利用服务器上的(.kml, .kmz).产生的图层。(.kml, .kmz);

GeoRSSLayer,利用服务器上的GeoRSS文件产生的图层。

...

显然,这些图层可以来自不同服务。对于arcgis for server发布出来的地图,在服务上右键选中property可以看服务地址:例如为http://localhost/arcgis/services/zy/MapServer,但实际引用方法为:http://localhost/ArcGIS/rest/services/zy/MapServer,可以将该地址复制到浏览器地址查看是否正确

图层对象里实际上可以包含多个图层,每个图层的在特定地图比例尺范围内的可见性一般在发布时就设置好了(就应该设置好),要注意这一点。


三、在地图上绘制图形

     自绘制图形即Graphic对象,一般都创建在GraphicLayer,每个Map至少缺省带一个GraphicLayer,可以创建多个,以实现分层管理,但在某个具体的业务中,将业务数据组织在一个图层中是有便利的,虽然从系统的角度不可取。Graphic 对象实际上包括一个 geometry,一个 symbol和一组属性(或一个infoTemplate),常用的geometry对象主要有Point、Polyline、Polygon等,用于确定Graphic的位置;常用的符号对象有SimpleMarkerSymbol、SimpleLineSymbol、SimpleFillSymbol、TextSymbol等,用于确定图形对象的显示方式。属性主要是有关图形的其他语义信息,如长度、名称、隶属关系等。

  因此,想在地图背景上绘制图形,主要有以下几步:

  //使用dojo加载绘制模块

....

  require([

        "esri/map",

        "esri/graphic",

        "esri/geometry/Point",

        "esri/geometry/Polyline",

        "esri/geometry/Polygon",

        "esri/symbols/SimpleLineSymbol",

        "esri/symbols/SimpleFillSymbol",

        "esri/symbols/TextSymbol",

        "dojo/parser",

      "dojo/on",

        "dojo/domReady!"

      ], function(

        Map, Graphic,

        Point, Polyline, Polygon,

        SimpleLineSymbol, SimpleFillSymbol, TextSymbol,

        parser,on

      ) {

   ...

    });


//读入几何数据,如下读入一个箭头绘制的多边形数据,不同的对象读入数据的要求各不相同。

//你可以想象你是从数据库中读入的,反正不是ArcGIS直接支持的类型。

...

var arrow = new Polygon({

            "rings": [

              [

                [9862211, 6617856],

                [8922952, 5522055],

                [8922952, 5991684],

                [6105178, 5991684],

                [6105178, 7087485],

                [8922952, 7087485],

                [8922952, 7557114],

                [9862211, 6617856]

              ]

            ],

            "spatialReference": {

              "wkid": 102100

            }

          });

...

//创建符号对象,这里比较偷懒,全用缺省值,

//本质上,你可以根据数据的不同取值进行设置,从而实现应用数据需要的可视化效果

//当然,符号对象可以重用给多个图形对象。

...

var polygonSymbol = new SimpleFillSymbol();

...

//最后创建图形对象并加入GraphicLayer图层

...

map.graphics.add(new Graphic(arrow, polygonSymbol));

...

下面的代码是一步创建点的geometry对象、符号属性,以及根据infoTemplate赋予属性的例子,前提时数据你都准备好了。

   ...

var myPoint = {"geometry":{"x":-104.4140625,"y":69.2578125,

       "spatialReference":{"wkid":4326}},"attributes":{"XCoord":-104.4140625,

       "YCoord":69.2578125,"Plant":"Mesa Mint"},"symbol":{"color":[255,0,0,128],

       "size":12,"angle":0,"xoffset":0,"yoffset":0,"type":"esriSMS",

       "style":"esriSMSSquare","outline":{"color":[0,0,0,255],"width":1,

       "type":"esriSLS","style":"esriSLSSolid"}},

       "infoTemplate":{"title":"Vernal Pool Locations","content":"Latitude: ${YCoord} <br/>

        Longitude: ${XCoord} <br/> Plant Name:${Plant}"}

   };

   var gra = new Graphic(myPoint);

...

以下是一段最基础的在地图背景上显示自定义图形的全部代码:

<!DOCTYPE html>

<html>

<head>

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">

    <title>Edit Tools</title>

    <link rel="stylesheet" href="https://js.arcgis.com/3.18/dijit/themes/nihilo/nihilo.css">

    <link rel="stylesheet" href="https://js.arcgis.com/3.18/esri/css/esri.css">

    <style>

        html, body, #map {

            height: 100%;

            margin: 0;

            padding: 0;

        }

    </style>

    <script src="https://js.arcgis.com/3.18/"></script>

    <script>

      var map;

      require([

        "esri/map",

        "esri/graphic",

        "esri/geometry/Point",

        "esri/geometry/Polyline",

        "esri/geometry/Polygon",

        "esri/symbols/SimpleLineSymbol",

        "esri/symbols/SimpleFillSymbol",

        "esri/symbols/TextSymbol",

        "dojo/parser",

        "dojo/on",

        "dojo/domReady!"

      ], function(

        Map, Graphic,

        Point, Polyline, Polygon,

        SimpleLineSymbol, SimpleFillSymbol, TextSymbol,

        parser,on

      ) {

        parser.parse();

 //打开地图

        map = new Map("map", {

          basemap: "streets",

          center: [3.955, 59.338],

          zoom: 3

        });

    //用addGraphics函数关联load事件,以便在加载地图时完成图形创建

     map.on("load", addGraphics);

     //创建自绘制图形

        function addGraphics() {

          //创建图形符号对象

          var polygonSymbol = new SimpleFillSymbol();

          var polylineSymbol = new SimpleLineSymbol();

          var text = new TextSymbol("Editable Text");

          text.font.setSize("20pt");

       //创建Geometry

          var polyline = new Polyline({

            "paths":[

              [

                [-12484306,7244028],

                [-7318386,10061803],

                [-3013453,10727111]

              ]

            ],"spatialReference":{

              "wkid":102100

            }

          });

          var polygon = new Polygon({

            "rings": [

              [

                [-4226661, 8496372],

                [-3835304, 8731187],

                [-2269873, 9005137],

                [-1213208, 8613780],

                [-1017529, 8065879],

                [-1213208, 7478843],

                [-2230738, 6891806],

                [-2935181, 6735263],

                [-3522218, 6891806],

                [-3952711, 7165757],

                [-4265797, 7283164],

                [-4304933, 7635386],

                [-4304933, 7674521],

                [-4226661, 8496372]

              ]

            ],

            "spatialReference": {

              "wkid": 102100

            }

          });

          var arrow = new Polygon({

            "rings": [

              [

                [9862211, 6617856],

                [8922952, 5522055],

                [8922952, 5991684],

                [6105178, 5991684],

                [6105178, 7087485],

                [8922952, 7087485],

                [8922952, 7557114],

                [9862211, 6617856]

              ]

            ],

            "spatialReference": {

              "wkid": 102100

            }

          });

          var triangle = new Polygon({

            "rings": [

              [

                [2426417, 8535508],

                [4304933, 12292541],

                [6183449, 8535508],

                [2426417, 8535508]

              ]

            ],

            "spatialReference": {

              "wkid": 102100

            }

          });

          var point = new Point(-40, 35);

       //创建图形对象并加入图层

          map.graphics.add(new Graphic(polyline, polylineSymbol));

          map.graphics.add(new Graphic(polygon, polygonSymbol));

          map.graphics.add(new Graphic(arrow, polygonSymbol));

          map.graphics.add(new Graphic(triangle, polygonSymbol));

          map.graphics.add(new Graphic(point, text));

        }       

      });

    </script>

</head>

<body>

    <div id="map"></div>

</body>

</html>


运行效果如下图所示:

    当然,如果我们的应用数据全部由Arcgis维护,在地图上显示自己的应用信息就和显示地图一样简单,常用FeatureLayer图层对象进行此类数据的管理。


四、处理事件和消息

    (1)地图有关的事件

    和Map有关的事件,常用的主要有”load \unload \layer-add \layer-remove \click\dbl-click、mouse-down \mouse-move \mouse-up \ key-down \key-up”等,前面已经接触到不少次”load”事件的应用了。下面是鼠标在地图上单击事件的例子,功能很简单,就是单击后弹出对话框显示处单击的屏幕位置坐标和地理位置坐标:

    ...

     map.on( "click", myClickHandler);

     ...

     function myClickHandler(evt) {

        alert("User clicked at " +

        evt.screenPoint.x + ", " + evt.screenPoint.y +

            " on the screen. The map coordinate at this point is " +

            evt.mapPoint.x + ", " + evt.mapPoint.y

        );

    }

         ...

    (2)特定Layer有关的事件

    特别是GraphicLayer等用户放置业务数据的图层,常用的主要有 \click\dbl-click\mouse-over \ graphic-add \graphic-remove\graphic-draw等,前三个一般用来查询图上目标,后两个通常用于数据变化后是否保存图形等处理,graphic-draw则用来控制显示的刷新,这里的刷新除非是图上数据变化导致应用据数需要重新导入,导致显示可能需要自行变化,才需要处理,否则,一般arcgis都给你做好了,不需费心。

      ...

//open图层

var incidentLayer = new FeatureLayer(

"https://sampleserver3.arcgisonline.com/ArcGIS/rest/services/SanFrancisco/311Incidents/FeatureServer/0", {

          mode: FeatureLayer.MODE_ONDEMAND,

          outFields: ["*"],

          id: "incidentLayer"

        });


incidentLayer.setSelectionSymbol(

          new SimpleMarkerSymbol().setColor(new Color("red"))

 );

map.addLayers([incidentLayer]);

...

//设置图层目标单击事件处理程序

//这里是事件关联与处理程序定义在一起的做法。

incidentLayer.on("click", function(evt) {

            graphicAttributes = evt.graphic.attributes;

            title = graphicAttributes.req_type;

            content = "<b>Date Reported: </b>" + graphicAttributes.req_date

                    + "<br><b>Address: </b>" + graphicAttributes.address

                    + "<br><b>District: </b>" + graphicAttributes.district;

            relatedQuery.objectIds = [graphicAttributes.objectid];

         

            incidentLayer.queryRelatedFeatures(relatedQuery, function(relatedRecords) {

              var fset = relatedRecords[graphicAttributes.objectid];

              var count = (fset) ? fset.features.length : 0;

              content = content + "<br><hr><br><i><span id='numPeople'>" + count +

                    "</span> people think this is important.</i>";

        content = content + "<br><br><img style='cursor:pointer' src='images/thumbsup.jpeg'  onclick='voteOnIncident(" + graphicAttributes.objectid + ");'>";

              map.infoWindow.setTitle(title);

              map.infoWindow.setContent(content);

              map.infoWindow.show(evt.screenPoint, map.getInfoWindowAnchor(evt.screenPoint));

            });

          });

   }

     ....

    (3)图形绘制事件

图形最重要的事件消息处理,是在图形的绘制编辑中。在交互输入中,esri/toolbars/draw提供有关绘制动作处理函数, esri/toolbars/Edit 提供目标图形编辑处理函数,这两个包提供的事件和编辑能力是极为重要的,要重点掌握。

处理绘制动作事件的过程主要是:

...

//引入Draw模块

require([ "esri/Darw", ... ], function(Draw, ... ){

   var tb;

   ...

   tb = new Draw(map);

   //关联draw-end事件处理对象

   tb.on("draw-end", addGraphic);

   //选中激活绘图工具

   tb.activate(point); //画点

   ...

   //定义绘制结束事件处理函数

  //将数据存入GraphicaLayer中。

   function addGraphic(evt) {

                //deactivate the toolbar and clear existing graphics

                tb.deactivate();

                map.enableMapNavigation();

                // figure out which symbol to use

                var symbol;

                if (evt.geometry.type === "point" || evt.geometry.type === "multipoint") {

                     symbol = markerSymbol;

                } else if (evt.geometry.type === "line" || evt.geometry.type === "polyline") {

                     symbol = lineSymbol;

                }

                else {

                    symbol = fillSymbol;

                }

                //创建图形对象加到地图缺省的GraphicLayer中

                //实际上,应在自己的服务器上创建一个

                //可保存的GraphicLayer

                map.graphics.add(new Graphic(evt.geometry, symbol));

}

...

});

绘制工具最常用的绘制动作包括这些类型,point、multipoint、line、polyline、freehandpolyline、triangle、rectangle、circle、ellipse、polygon、freehandpolygon、arrow等。

(4)图形编辑事件

处理编辑动作的主要过程是:

 ....

require([ "esri/toolbars/edit", "dojo/_base/event", "dojo/parser",...],

        function ( Edit, event, parser,... ) {

...

//创建编辑工具

var editTb = new Edit(map);

...

//单击选中目标时激活编辑工具

map.graphics.on("click", function (evt) {

    //检查没有处于绘图状态

    if (!drawediting) {

        event.stop(evt);

        //设置编辑工具可以具备的编辑动作类型

        var tool = 0;

        tool = tool | Edit.MOVE | Edit.EDIT_VERTICES | Edit.SCALE | Edit.EDIT_TEXT;

        editTb.activate(tool, evt.graphic);

    }

 });

 //当单击非目标上时,取消编辑工具

  map.on("click", function (evt) {

        if (!drawediting)

              editTb.deactivate();

});

....

    上述过程,已经基本能够完成绝大多数图形编辑的工作,如果在编辑完成后还需要进一步做工作,则需要通过监视Layer的事件进行相关的进一步处置,如保存数据等。



世界读书日

关于Dojo的基本知识:

    ArcGIS API for JavaScript 是基于Dojo开发的, Dojo包括按钮、格网、树、图表和其他的界面组件,并主要由3部分组成:

(1)Core-核心包;

(2)Dijit-主题界面组件;

(3)DojoX-各种扩展组件,如图表等。   

ArcGIS API for JavaScript 完全支持利用异步模块定义(Asynchronous Module Definition,AMD)风格的代码创建JavaScript 对象和模块。由于使用Dojo对Javascript的部分能力进行了封装,因此,要理解其原理,必须理解以下几个Dojo命令,这都属于Dojo的core部分,由于Dojo也在不断发展,需注意现行版本与以前的区别。

     (1)dojo.require: 类似 <script> 标签,用于从特定包中导入JS脚本到当前脚本页。

...

// legacy

dojo.require("esri.map");

// AMD

require(["esri/map", ... ], function(Map, ... ){ ... });

...

因此,如果在后续脚本中用到API的对象或方法等,都应用require先申明一下,如:

    ....

    require([

        "esri/map",

        "esri/tasks/GeometryService",

        "esri/layers/ArcGISTiledMapServiceLayer",

        "esri/layers/FeatureLayer",

        "esri/Color",

        "esri/symbols/SimpleMarkerSymbol",

        "esri/symbols/SimpleLineSymbol",

        "esri/dijit/editing/Editor",

        "esri/dijit/editing/TemplatePicker",

        "esri/config",

        "dojo/i18n!esri/nls/jsapi",

        "dojo/_base/array", "dojo/parser", "dojo/keys",

        "dijit/layout/BorderContainer", "dijit/layout/ContentPane",

        "dojo/domReady!"

      ], function(

         Map, GeometryService,

         ArcGISTiledMapServiceLayer, FeatureLayer,

         Color, SimpleMarkerSymbol, SimpleLineSymbol,

         Editor, TemplatePicker,

         esriConfig, jsapiBundle,

         arrayUtils, parser, keys

       ) {

      //代码区

   });

     (2)dojo.ready (or dojo.addOnLoad): 类似 <body onload="">标签. 它帮助注册页面加载时初始化的脚本模块。

...

// legacy

dojo.ready(init);

// AMD

require(["dojo/ready"], function(ready){

   ready(function(){

    // This function won't run until the DOM has loaded and other modules that register have run.

   });

});

...

     (3)dojo.connect: 类似DOM组件的JavaScript 函数Element.addEventListener和Element.attachEvent。 主要用于登记页面中或页面特定组件的事件、消息处理函数。

       ...

// legacy

dojo.connect(myMap, "onLoad", myLoadHandler);

// AMD

require(["esri/map", "dojo/on"], function(Map, on) {

  // ...

  on(myMap, "load", callback);

});

...

    (4)dojo.byId: 类似 JavaScript 函数document.getElementById(id),主要用于通过id获得页面中对象id

 ...  

dojo.byId("myInputField").value = myMap.id;

...


欢迎留言......


请大家关注公众号动态!

请大家关注公众号动态!

请大家关注公众号动态!



本文分享自微信公众号 - IT技术小咖(IT-arch)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部