JavaScript构建Web和ArcGIS Server应用实战

978-7-115-40362-9
作者: 【美】Eric Pimpler(派普勒)
译者: 张大伟
编辑: 胡俊英陈冀康

图书目录:

详情

本书是一本开发指南,按部就班地教授读者如何开发Web和移动的ArcGIS Server应用。通过和HTML/CSS/JavaScript等技术一起配合,你将掌握为地图添加直观的地理化图层信息,交互查询和显示空间数据,添加用户界面插件,访问地理信息任务等等。

图书摘要

版权信息

书名:JavaScript构建Web和ArcGIS Server应用实战

ISBN:978-7-115-40362-9

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

• 著    [美] Eric Pimpler

  译    张大伟

  责任编辑 陈冀康

• 人民邮电出版社出版发行  北京市丰台区成寿寺路11号

  邮编 100164  电子邮件 315@ptpress.com.cn

  网址 http://www.ptpress.com.cn

• 读者服务热线:(010)81055410

  反盗版热线:(010)81055315


Eric Pimpler是geospatialtraining.com网站的创始人和所有者,他有着20多年使用Esri、Google Earth/Maps及开源技术进行GIS解决方案的实施和教学经验。目前,他主要致力于使用Python进行ArcGIS脚本编程及使用JavaScript进行自定义的ArcGIS Server Web和手机应用程序的开发。另外,他还是Programming ArcGIS 10.1 with Python Cookbook一书的作者。

Eric获得了Texas A&M大学地理学士学位,另外他还获得了Texas State大学GIS应用地理硕士学位。


Copyright © 2014 Packt Publishing. First published in the English language under the title Building Web and Mobile ArcGIS Server Applications with JavaScript.

All rights reserved.

本书由英国Packt Publishing公司授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式或任何手段复制和传播。

版权所有,侵权必究。


ArcGIS Server是用于开发基于Web的GIS应用程序的主要平台,而JavaScript已经成为在这个平台上开发应用程序的主流语言之一。本书介绍了如何利用ArcGIS API for JavaScript来创建基于Web的GIS应用程序。

本书共12章,分别介绍了基本概念、创建地图和添加图层、添加图形到地图、特征图层、使用控件和工具栏、空间和属性查询、定位和查找特征、地址转换点和点转换地址、网络分析任务、地理处理任务、整合ArcGIS Online以及创建移动应用程序。附录部分介绍了利用ArcGIS模板和Dojo设计应用程序。

本书结构清晰、示例丰富,非常适合初学者和中级水平的GIS开发人员,也适合想要使用该平台进行应用开发的读者。


Eric的这本书,首先从最基础的HTML、CSS和JavaScript内容开始讲解,然后从ArcGIS API for JavaScript的各个技术点着手一步一步地介绍,每章在介绍理论知识的同时,还包括对知识点的练习。像这样理论和实践相结合的书籍特别适合对GIS开发感兴趣的初学者以及有一定GIS开发经验的初、中级开发人员阅读、参考。

本书的内容较多,涉及的知识点也比较广。工作之余进行翻译工作,无论是对语义的理解、案例的复现或模拟,还是对字句的斟酌,都颇为辛苦。不过本书的内容是我当前工作的一部分,也是我兴趣之所在。在推敲字句之时,常能有会心一笑,可谓苦中有乐。

在本书将要完成之际,我要将此书献给我亲爱的爸爸、妈妈,愿他们永远健康快乐!

我还要特别感谢我的妻子汪云妹,翻译本书的过程几乎占据了我所有的业余时间,如果没有她的理解、鼓励和支持,我难以想象自己能按时完成这项工作!

临近付梓之际,心中难免惴惴,虽然我尽力做了很多努力以避免错误,也广邀从事IT工作的同学和好友做了审阅,但是错误或不妥之处在所难免。如果各位读者发现了错误,请发送邮件到邮箱:zdw850828@163.com,我将尽我所能进行答复,并对你提供的帮助表示由衷的感谢。


ArcGIS Server是用于开发基于Web的GIS应用程序的主要平台。我们可以使用多种编程语言去开发基于 ArcGIS Server 的应用程序,包括 JavaScript、Flex 和 Silverlight。JavaScript已经成为在这个平台上开发应用程序的首选语言,因为它可以用在Web和移动应用程序中,并且在浏览器上不需要为应用程序安装插件。Flex和Silverlight两者都不太适合作为移动终端程序开发的语言,并且当应用程序运行在浏览器中时都需要用到插件。

本书将介绍如何利用ArcGIS API for JavaScript来创建基于Web的GIS应用程序。通过实用且容易上手的学习方式,我们将学会如何使用ArcGIS Server去开发功能齐全的应用程序,并形成在更高要求下的技能集。

学习如何创建地图,并从一系列资源(包括切片缓存和动态地图服务)中添加地理图层。另外,介绍如何将graphics添加到地图上及使用FeatureLayer输出地理特征到浏览器上。大部分应用程序还包括通过ArcGIS Server执行特定功能的任务。我们还将学习如何使用各种ArcGIS Server提供的任务,包括查询、定位特征、属性查找特征、地理处理任务等。最后,我们将很轻松地学会利用ArcGIS API for JavaScript开发移动应用程序。

第1章,HTML、CSS和JavaScript简介,介绍在利用ArcGIS API for JavaScript进行GIS应用程序开发之前,需要掌握的一些基本的HTML、CSS和JavaScript概念。

第2章,创建地图和添加图层,介绍如何创建地图并向这个地图上添加图层。我们将学习如何创建一个地图类的实例,为地图添加图层数据和在 Web 页面中展示内容。Map类是API中最基本的类,它为应用程序中的数据图层和任何后继活动提供容器。然而,地图只有添加了图层数据才能发挥作用。我们可以添加多种类型的数据图层到地图中,包括切片缓存图、动态图和特征图。读者将会在本章中学习到这些图层类型的更多内容。

第3章,添加图形到地图,向读者介绍如何在地图上用GraphicsLayer显示临时点、线和面。GraphicsLayer是一种独立图层,可以显示在其他图层上,并存储所有和地图相关的图形。

第4章,特征图层,它除了继承GraphicsLayer之外还提供了额外的功能,比如执行查询和选择的功能。特征图层还可用作在线特征编辑。特征图层与缓存切片和动态地图服务图层不同,因为特征图层会将地理几何信息绘制并存储到客户浏览器中。特征图层极大地减少了和服务器端的往返时间。一个客户端可以请求它需要的特征,对这些特征执行选择和查询而不需要向服务器端请求更多信息。

第5章,使用控件和工具栏,介绍拿来即用的控件。我们可以直接将其引入到应用程序中来提高生产率,包括BasemapGalleryBookmarksPrintGeocodingLegendMeasurementScalebarGaugeOverviewMap等控件。另外,ArcGIS API for JavaScript还包括helper类,它用来将各种工具栏添加到你的应用程序中,比如导航和绘制工具栏。

第6章,空间和属性查询,介绍ArcGIS Server查询任务,它允许对已经暴露在一个地图服务中的数据图层执行属性和空间查询操作。我们也可以组合这些查询类型去执行一个联合体的属性和空间查询。

第7章,定位和查找特征,介绍在任何GIS应用程序中都存在的两个常用操作。要求用户以定位的形式单击地图上的一个特征,或者以查找特征的方式去执行一个查询操作。在这两种情况下,返回特征的详细信息。在本章中,读者将学会如何使用IdentifyTaskFindTask对象去获取特征的信息。

第8章,地址转换点和点转换地址,介绍使用Locator(定位)任务执行地理编码和逆地理编码。地理编码的过程是为地址分配坐标,而逆地理编码则是为坐标分配地址。

第9章,网络分析任务,允许在道路网络上执行分析,比如查找从一个地点到另一个地点的最佳路径、查找最近的学校、定位一个位置附近的服务区或者响应一系列服务车辆的订单集。

第10章,地理处理任务,允许运行通过ModelBuilder在ArcGISDesktop上建立自定义模型。模型的运行方式是自动方式,不是在桌面环境下就是经过集中式服务器通过Web应用程序实现。任何在ArcToolbox中的工具,不论它是ArcGIS系统工具还是我们创建的自定义工具,都可以用在模型中并且和其他工具关联在一起。这些模型一旦构建后,就能运行在一台集中式服务器中,并且通过Web应用程序访问。在本章中,我们将通过ArcGIS API for JavaScript去实践如何使用这些地理处理任务。

第11章,整合ArcGIS Online,阐述如何使用ArcGIS API for JavaScript来获取ArcGIS.com创建的数据和地图。ArcGIS.com是提供地图和其他类型地理信息的网站。在这个站点上,我们将发现用于创建和共享地图的应用程序,还可以找到可供查看和使用的有用底图、数据、应用程序和工具。另外,我们也可以加入该社区。对于应用程序开发人员来说,真正令人激动的消息是可以通过ArcGIS API for JavaScript集成ArcGIS.com内容到自定义开发的应用程序中。在本章中,我们将探索到ArcGIS.com地图是如何添加到应用程序中的。

第12章,创建移动应用程序,阐述如何使用ArcGIS API for JavaScript来创建移动GIS应用程序。ArcGIS Server当前支持iOS、Android和BlackBerry操作系统。API集成在dojox/mobile中。在本章中,我们将学习精简的API,它使得Web地图应用程序通过Web-kit浏览器和手势支持变为可能。

附录,利用ArcGIS模板和Dojo设计应用程序,介绍设计和创建用户界面接口这个对于大多数Web开发人员来说最难的任务。ArcGIS API for JavaScript和Dojo极大地简化了这个任务。Dojo的布局Dijits提供一个简单、有效的方式去创建应用程序布局,美国环境系统研究所(Environmental Systems Research Institute,ESRI)已经提供了一系列的示例应用程序布局和模板来供你安排和快速运行。在附录中,读者将学到快速设计应用程序的技巧。

为了完成本书中的练习,需要访问浏览器,推荐使用Google Chrome或者Firefox。

如果你是一个打算使用ArcGIS Server和ArcGIS API for JavaScript技术进行Web和移动GIS应用程序开发的应用开发人员,那么这本书是最合适不过了。本书主要面向初学者和中级水平的GIS开发人员,或者在过去没有进行过GIS应用程序开发,但是现在正致力于在这个平台实施解决方案的人。先前没有ArcGIS Server、JavaScript、HTML、CSS经验的读者,这本书肯定对你很有帮助。

在本书中,你会发现多种文本样式用以区分不同类型的信息。下面是一些这些样式的例子以及对它们含义的说明。

在文本、数据库表名、文件夹名、文件名、文件后缀名、路径名、虚拟URLs、用户输入和推特标签中的代码这样显示:“将onorientationchange()事件添加到<body>标签。”

一段代码的设置如下。

routeParams = new RouteParameters();
routeParams.stops = new FeatureSet();
routeParams.outSpatialReference = { wkid:4326};
routeParams.stops.features.push(stop1);
routeParams.stops.features.push(stop2);

当我们想让你注意一个特殊的代码段时,相关的行或内容会加粗。

function computeServiceArea(evt) { map.graphics.clear(); var pointSymbol = new SimpleMarkerSymbol(); pointSymbol.setOutline = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,new Color([255,0,1]),1); pointSymbol.setSize(14); pointSymbol.setColor(new Color([0,255,0,0.25]));
}

新术语重要词汇加粗显示。比如屏幕上看见的、菜单中或者对话框中的单词,像这样出现在文本中:“单击Run按钮”。


警告或者重要笔记像这样显示在一个框中。


提示和技巧像这样显示。

欢迎我们的读者进行反馈,让我们知道你们对这本书的看法——不论是喜欢还是不喜欢。读者的反馈能够帮助我们写出更多对读者真正有用的内容。

向我们发送反馈,仅需发送电子邮件到feedback@packtpub.com,并且在邮件消息中提到本书的标题即可。

假如某个主题是你的专长,并且有兴趣写作一本书或者贡献部分章节的话,请访问www.packtpub.com/authors查看我们的作者指南。

现在你成为了Packt出版社的一名尊敬的读者,为使你的消费物超所值,我们也为你准备了丰富的内容。

你可以在http://www.packtpub.com上的账户下载你所购买的所有Packt书籍的示例代码文件。假如你在其他地方购买了本书,可以访问http://www.packtpub.com/support,并注册以通过电子邮件直接获取这些文件。

尽管我们已经全力保证内容的准确性,但错误在所难免。如果你在我们的书中发现了错误,不论是文本还是代码,如果你能报告给我们的话,我们会很感激。通过这样的方式,可以避免让其他读者对内容产生困惑,并且能帮助我们改进本书的后续版本。如果你发现了任何错误,请通过访问网站http://www.packtpub.com/submit-errata来提交错误报告。选择你自己的书,单击errata submission form链接,然后输入错误细节描述即可。一旦你的勘误表通过了验证,你所提交的内容将被接受并且勘误表将被上传到我们的网站,或添加到现有勘误表列表下的关于这个标题的勘误部分。任何现有的勘误表都可以通过在网站http://www.packtpub.com/support上选择你的标题来查看。

互联网上的盗版现象非常多见,我们Packt非常注重对版权和许可证的保护。如果你遇到在互联网上以任何形式非法复制我们的作品,请及时提供给我们地址或网站名称,以便及时补救。

请将涉嫌盗版的材料链接通过copyright@packtpub.com告知我们。

我们非常感谢你帮助并保护我们的作者,我们将竭诚为你带来更有价值的内容。

假如关于本书你有任何方面的问题,都可以通过questions@packtpub.com与我们取得联系,我们将尽力解决。


Pouria Amirian是GIS和计算机科学方向的讲师、研究员,他还是爱尔兰国立大学、美努斯学院的科研工作者。除了和爱尔兰国立大学合作外,他还与德国、法国和英国等国家的世界一流大学有多个科技学术方面的合作。他是2013年由Wiley出版的ArcGIS开发畅销书Beginning ArcGIS for Desktop Development using .NET的作者。他在小型规模到企业分布式、面向服务(geospatial)的信息系统的设计及开发方面有着丰富的经验。Amirian博士目前致力于前沿的技术研究,并且在大数据(geospatial)的项目开发和NoSQL数据库方面有着丰富的经验,他还是与以上主题相关的多本图书的技术编辑,你可以通过pouriaamirian.arcobjects@gmail.com和他取得联系。

我要感谢我的朋友MajidFarahani博士,在我的职业生涯中给予我的支持、理解和鼓励。我还要感谢作者和技术审稿组,是他们让这本书成为一个有趣的项目。

——Pouria Amirian

Ken Doman的大部分精力都投入到了计算机事业中,并在业余时间也专注于该领域。他毕业于莱斯大学并取得生物学士学位。自此之后,他辗转于多个领域,直到他被邀请为他的家乡(德克萨斯州切罗基县的杰克逊维尔)创建一个GIS部门。起初,他用一整个鞋柜的笔记本纸张来保存地址数据库。不久之后,他便发布了他们社区的第一个在线地图。他也因此迷上了发布Web地图。

Ken目前在Bruce Harris and Associates公司担任GIS Web开发工程师,该公司是一个私营企业,主要为美国各地区提供GIS服务和产品。在那里,他从事一系列的技术工作,帮助县和市政府部门在Web浏览器中提供有效的数据。

这本书是Ken第一本参与审阅的书,他对此有很高的期望,后面他还会有其他书籍陆续出版。

我首先要感谢我的妻子Luann,感谢她的爱与支持。她言语间的鼓励让我对待此书认真负责。我还要感谢上苍赐予我这样好的机会,同时感谢Bruce Harris and Associates公司,以及佛罗里达州的普兰特城和德克萨斯州的杰克逊维尔等城市,让我有机会学习更多与GIS有关的知识,它们对我的职业生涯有很大的帮助。

——Ken Doman

Joseph Saltenberger在一个GIS软件公司担任数据分析员,专门为消防和EMS部门提供专业的空间决策支持系统。他毕业于洪堡州立大学,并获得自然资源(GIS 和遥感)学士学位,在圣地亚哥州立大学他还获得了地理(地理信息重点科学)硕士学位。他在学术和职业生涯中一直专注于使用GIS进行数据管理和分析以及定制开发GIS应用程序。


在开始使用ArcGIS API for JavaScript进行GIS应用程序开发之前,你需要理解一些基本概念。对于那些已经熟悉HTML、JavaScript和CSS的读者来说,就请跳过这一章直接到下一章进行学习。但是,如果你刚开始了解这些概念,请继续阅读。我们将从基础概念开始介绍这些主题,这足以让你入门。关于这些主题的更高层次的学习,有很多学习资源提供,包括书籍和在线教程。你可以参考附录“利用ArcGIS模板和Dojo设计应用程序”来获取一系列综合的资源。

在本章中,我们将涵盖以下主题。

在深入地图创建和图层添加细节内容前,你需要了解当使用ArcGIS API for JavaScript开发应用程序时,代码上下文的位置。你所编写的代码将会放在一个HTML页面或者JavaScript文件中,HTML文件的后缀名通常为.html或者.htm,JavaScript文件的后缀名为.js。一旦创建了一个基本的HTML页面,你就可以使用ArcGIS API for JavaScript按所需的步骤来创建一个基本的地图。

网页的核心是HTML文件。对这个基础文件进行编码很重要,因为它组成了应用程序的其余部分。你在基础的HTML代码中所犯的错误将会在JavaScript代码访问这些HTML标签时发生故障。

下面的示例代码是一个非常简单的HTML页面。这个例子可以简单地从一个HTML页面得到。它仅包含了基本的HTML标签——<DOCTYPE><html><head><title><body>。使用你偏好的文本或者网页编辑器来键入下列代码。我使用Notepad++,但是还有其他多种不错的编辑器。保存该示例为helloworld.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0.1//EN" "http://www.w3.org/TR/ html4/strict.dtd">

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

  </head>
  <body>
      Hello World
  </body>
</html>

当前使用的HTML类型有多种。最新的HTML5正备受关注,你将看到很多新应用程序的开发都是基于HTML5实现的。因此,我们将在全书中重点关注HTML5。然而,我也需要让你认识到还有其他种类的HTML在使用,最常用的是HTML4.01(如先前的示例代码)和XHTML 1.0。


下载示例代码

你可以从你在http://www.packtpub.com的账户上下载所有购买自Packt书籍的示例代码文件。如果你从其他地方购买本书的话,你可以访问http://www.packtpub.com/support,并注册来获取以邮件发送给你的文件。

你的HTML页面的第一行包含了DOCTYPE声明。它用来通知浏览器如何来解析这个HTML页面。在这本书中我们重点放在HTML5上,所以下面的示例中你看到的是HTML5的DOCTYPE声名。其他常用的两种DOCTYPE声明是HTML4.01严格和XHTML 1.0严格。

HTML 5使用下面的代码。

<!DOCTYPE html>

HTML 4.01严格使用下列代码。

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/ html4/strict.dtd">

XHTML 1.0严格使用下列代码。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3. org/TR/xhtml1/DTD/xhtml1-strict.dtd">

所有的Web页面至少要包含<html><head><body>标签。<html>标签定义了整个HTML文档,其他的标签都必须放在该标签内部。定义Web页面如何在浏览器中呈现的标签都是放在<body>标签内部的,比如,地图应用程序的<body>标签中要包含一个<div>标签,用作呈现地图的容器。

在浏览器中加载helloworld.html页面,如图1-1所示。大部分你编写的ArcGIS API for JavaScript代码都会放置在<head></head>标签之间的<script>标签内或者在一个单独的JavaScript文件内部。随着经验的丰富,你可能开始将JavaScript代码放置在一个或多个JavaScript文件当中,然后从JavaScript部分引用它们,稍后我们将研究这个内容。现在只要注意将你的代码放在<head>标签内部即可。

图1-1 helloworld.html运行效果

正如前面提到的那样,正确编写HTML标签很重要。你肯定会说这些都是理所当然的啦。然而我们如何知道编写的HTML是正确的呢?你可以使用一系列HTML代码验证器来检查HTML。W3C HTML验证器(http://validator.w3.org/)如图1-2所示,你可以通过上传文件或者直接输入URI来验证HTML代码。

图1-2 W3C HTML验证器

假设你的HTML代码已经成功验证的话,你将看到图1-3所示的验证成功的屏幕消息。

图1-3 HTML验证成功

此外,对于发现的任何问题会以红色显示来报告错误信息,然后根据错误描述的细节,我们可以很容易地改正错误,如图1-4所示。通常一个错误会导致很多其他错误,因此看到很长的错误项列表的话并不稀奇。如果出现这种情况,请不要慌张,修正一个错误通常会解决很多其他的问题。

图1-4 HTML验证失败

要改正上面文档中出现的错误,你需要将文本HelloWorld使用段落标签包裹起来,类似<p>Hello World</p>

顾名思义,ArcGIS API for JavaScript要求你使用JavaScript语言来开发应用程序,所以在开始创建应用程序之前你需要了解一些基础的JavaScript编程概念。

JavaScript是嵌入在所有Web浏览器中的一个轻量级的脚本语言。虽然JavaScript能在浏览器环境之外的其他应用程序中存在,但是众所周知它是和Web应用程序集成在一起的。

所有主流的浏览器,包括Internet Explorer、Firefox和Chrome等都嵌入了JavaScript。Web应用程序中使用JavaScript可以让我们创建不需要和服务器往返就可以获取数据的动态应用程序的能力,这样应用程序具有响应更加及时和用户交互友好的特性。然而,JavaScript并不具备提交请求到服务器的能力,其核心技术体现在异步JavaScript和XML(AJAX)堆栈中。


一种常见的误解是认为JavaScript是Java的简化版,但两种语言实际上除了名字相似外没有任何关联。

在编写JavaScript代码时,最佳的做法是使用注释。这些注释最起码要包括代码的作者、最后一版的日期和代码的作用。另外,在代码的各个时期,都应该通过包含注释部分来定义应用程序特定部分的作用。该注释文档的作用是当下次代码需要更新时,能让你或者其他程序员可以进行快速处理。

任何添加到代码中的注释都不会被执行。注释部分会直接被JavaScript解释器忽略。JavaScript中的注释有多种方式,包括单行注释和多行注释。单行注释以//开始,任何你添加的额外字符都要在该行中。下列示例代码显示了单行注释是如何创建的:

//this is a single line comment. This line will not be executed

JavaScript中的多行注释以/*开始,以*/结束,其中间的任何一行都是注释的内容,不会被执行。下列示例代码显示的是多行注释:

/*
 Copyright 2012 Google Inc.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at http://www.apache.org/licenses/ LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and limitations under the License.
*/

使用任何编程语言,对变量的理解都是最基本的要求。变量就是我们用来和某种类型的数据值关联的名字。简单地说,这些变量就是在计算机内存中开辟出来的一块用来存储数据的区域。

你可以将变量理解成一个盒子,它有一个名字并包括某种类型的数据。当初始化这个变量时,它一直为空直到被分配数据。一般地,变量为我们提供了存储和操作数据的能力。图1-5所示为当我们创建一个变量ssn时,起初这个变量为空,然后赋值为450-63-3567。变量的赋值类型有很多种,包括数值型、字符串型、布尔类型、对象类型和数组类型等。

图1-5 变量赋值

在JavaScript中,通过var关键字来声明变量。一般地,为变量分配变量名完全取决于你自己。然而,创建一个变量时你需要遵循一些规则。变量可以同时包含字母和数字,但是不能以数字开头,通常变量名以字母或下划线开头。此外,变量名中不允许出现空格和特殊字符,如%和&。除此之外,你可以自由地创建变量名,但是你应当让分配的变量名能描述出数据的意义。使用同一个var关键字来声明多个变量也是合法的,如下列代码所示。

var i,j,k;

你还可以在声明变量的同时对其进行赋值,如下列代码所示。

var i = 10;
var j = 20;
var k = 30;

你或许已经发现每个JavaScript语句都是以分号结束。分号意味着JavaScript语句的结束,在JavaScript中都应当包括分号。

需要特别强调的是,JavaScript是一种区分大小写的脚本语言,因此在使用的时候要非常小心,否则会导致代码中出现一些难以跟踪的bug。所有的变量、关键字、函数和标识符都必须是一串大写字母。JavaScript区分大小写跟HTML不区分大小写常常令人感到混淆,这对于JavaScript开发新手来说是一个绊脚石。在下列代码段中,我们创建了三个变量,拼写全部一样。但是,因为它们不是相同的大小写方式,所以最后定义出来的是三个不同的变量。

var myName = 'Eric';
var myname = 'John';
var MyName = 'Joe';

JavaScript支持多种数据类型,你可以使用它们来分配变量。不像其他强类型语言,比如.NET或者C++,JavaScript是一种弱类型语言,意味着你不必为变量指定数据类型,JavaScript解释器会直接帮你判断。你可以为变量分配字符串、数值、布尔true/false值、数组或者对象类型的值。

数值和字符串值大部分都很简单。字符串是通过单引号或者双引号包裹的简单文本,如下列代码所示。

varbaseMapLayer = "Terrain";
var operationalLayer = 'Parcels';

数值类型不需要使用引号包裹,它可以是整型数或者浮点数。

var currentMonth = 12;
var layered = 3;
var speed = 34.35;

有一点我要向程序开发新手指出的是,数值类型可以通过使用单引号或者双引号分配给字符串变量。对于一些开发新手来说有时会为此感到困惑。比如,3.14没有使用单引号或者双引号内是一个数值类型,然而使用了单引号或者双引号,那么它就是一个字符串类型。

其他数据类型包括简单的true或false值的布尔型。数组是一系列数据值的集合,一个数组基本上可作为多个值的容器。比如,你可以在一个数组内存储地理数据图层名称列表并根据需要单独访问它们。

数组允许在一个单独变量中存储多个值。比如,希望存储所有添加到地图上的图层名称,你可以使用一个数组将所有图层的名称保存在一个单独的变量中,而不需要为每一个图层创建一个变量。然后你在数组中通过使用for循环以及一个索引值来引用其中的每个值。下列示例代码显示了一种在JavaScript中创建数组的方式。

var myLayers = new Array();
myLayers[0] = "Parcels";
myLayers[1] = "Streets";
myLayers[2] = "Streams";

你还可以简化上述数组变量的创建方式,使用中括号来包裹通过逗号分割的列表,如下列代码所示。

var myLayers = ["Parcels","Streets","Streams"];

你可以通过使用索引来访问数组中的元素,如下列代码所示。数组访问是从索引0开始的,即数组中的第一项占据第0个位置,数组中的每个连续项的索引是依次递增的。

var layerName = myLayers[0]; //returns Parcels

JavaScript中的if/else语句和其他编程语言一样,是一种允许在代码中进行条件选择的控制语句。这种类型的语句在代码段的最顶部执行条件判断,假如判断返回的值是true,然后跟if代码块相关的语句将会执行。假如判断的返回值是false,则执行跳转到elseif代码块中。这种模式将一直进行下去,直到返回一个判断为true的值或者执行到达else语句。下列示例代码显示了该条件语句是如何执行的。

var layerName = 'streets';
if(layerName == 'aerial'){
   alert("An aerial map");
}
else if(layerName == 'hybrid'){
   alert("A hybrid map");
}
else {
   alert("A street map");
}

循环语句能让我们反复地运行同一代码块。JavaScript中有两种基本的循环机制。for循环执行指定次数的代码块。while循环当条件为true时执行代码块,一旦条件变为false,循环机制将结束。

下列示例代码显示的是for循环语法。你会注意到它有一个整型的初始值和条件语句,你还可以提供一个增量,在当前值比最后的值小的条件下,for循环内部的代码块将被执行。

for (start value; condition statement; increment)
{
  the code block to be executed
}

下列代码中初始值设置成0并赋值给一个名为i的变量,条件语句是当i小于或者等于10,然后i值每次循环递增1,使用的是++操作符,每循环一次,打印输出i的值。

var i = 0;
for (i =0; i <= 10; i++){
    document.write("The number is "+ i);
    document.write("<br/>");
}

JavaScript中的另外一种循环机制是while循环,这种循环用在当条件为true时执行代码块;一旦条件变为false,则停止执行循环。while循环接受一个作为条件判断的参数。如下列代码所示,当i小于或者等于10时,代码块将被执行。初始条件下,i被设置成值0。在代码块的最后,你会注意到i递增1(i = i +1)。

var i = 0;
while (i <= 10)
{
    document.write("The number is "+ i);
    document.write("<br/>");
    i = i + 1;
}

现在让我们来介绍函数这个重要主题。函数是简单命名的代码块,在调用时被执行。在本书中你编写的和开发工作中的大部分代码都会用到函数。

最佳实践是将代码分割成按照细小的离散单元进行操作的函数。这些代码块通常定义在Web页面的<head>中的<script>标签内,也可以定义在<body>中。然而,大多数情况下,还是将函数定义在<head>中,以保证页面加载后能找到这些函数。

函数通过使用关键字function后面跟上函数名称来创建,所需的任何变量可以作为参数传递到函数中执行。如果事件调用代码中有返回值的话,需要使用return关键字来返回数据。

函数还可以接受参数变量来传递信息到函数中。下列代码中,函数prod()传递两个变量:ab。以变量形式的参数信息,可以在函数内部使用。

var x;
function multiplyValues(a,b)
{
    x = a * b;
    return x;  
}

现在我们已经掌握了一些基本的JavaScript概念,我们将在这部分介绍最重要的概念。为了能更有效地使用ArcGIS API for JavaScript进行地图应用程序开发,你需要对对象有一个基本的理解。因此,对象是一个需要你了解和掌握如何进行Web地图应用程序开发的关键概念。

ArcGIS API for JavaScript中广泛使用对象。我们将详细讲述编程类库的细节,但是现在我们主要针对高级概念进行介绍。对象是一个复杂的结构,能够将多个数据值和行为统一到一个单独的结构中。对象和先前的数据类型比如数值型、字符串型和布尔型有着很大的不同,那些类型仅能够保存一个单值,而对象则有着更复杂的结构。

对象由数据和行为组成。数据以属性形式包含对象信息。比如,ArcGIS API for JavaScript中的Map对象有一系列的属性,包括地图范围、与地图相关的图形、地图的高度和宽度、与地图相关的图层ID和其他属性,这些属性包含了该对象的信息。

对象也有行为,也就是我们常说的方法,我们也可以将构造函数和事件组合到方法中。map中方法的行为包括添加图层、设置地图范围或者获取地图比例尺。

构造函数是用来创建对象新实例的函数。一些对象还可以传递参数到构造函数中来获得创建对象的更多控制。下列示例代码显示的是创建Map对象新实例的构造函数是如何使用的。你可以看出这是一个构造函数,因为此处使用了醒目的new关键字。new关键字跟在对象名后面,在为对象定义构造函数时可以使用任意参数来控制该新对象。这种情况下,我们创建一个新的Map对象并存储在一个名为map的变量中。三个参数传递到构造函数中用来控制Map对象的某些属性,包括底图、地图中心和缩放尺度。

var map = new Map("mapDiv",{
  basemap:"streets",
  center:[-117.148,32.706],//经度和纬度
  zoom:12
});

事件是发生在对象上的行为,通过最终用户或者应用程序触发。这些事件包括地图单击、鼠标移动或添加图层到地图上。

属性和方法是通过点符号来分割对象实例的名字与属性或方法的。数据可以通过使用参数传递到方法中。下列代码第一行中,我们传递一个名为pt的变量到map.centerAt(pt)方法中。

var theExtent = map.extent;
var graphics = map.graphics;

方法也是类似的情况,只不过方法名后面还有括号。数据可以通过使用参数传递到方法中。下列代码第一行,我们传递一个名为pt的变量到map.centerAt(pt)中。

map.centerAt(pt);
map.panRight();

级联样式表(CSS)是描述网页中HTML元素如何显示的一门语言。例如,CSS通常用来定义一个或多个页面中的常见的样式元素,比如字体、背景颜色、字体大小、链接颜色和其他多种与网页视觉设计相关的方面。让我们看下面的代码片段。

<style>
  html, body {
    height: 100%;
    width: 100%;
    margin: 0;
    padding: 0;
  }

  #map{

    padding:0;
    border:solid 2px #94C7BA;
    margin:5px;
  }
  #header {
    border: solid 2px #94C7BA;
    padding-top:5px;
    padding-left:10px;
    background-color:white;

    color:#594735;

    font-size:14pt;
    text-align:left;
    font-weight:bold;
    height:35px;
    margin:5px;
    overflow:hidden;
  }
  .roundedCorners{
    -webkit-border-radius: 4px;
    -moz-border-radius: 4px;
    border-radius: 4px;
  }
  .shadow{

    -webkit-box-shadow: 0px 4px 8px #adadad;
    -moz-box-shadow: 0px 4px 8px #adadad;
    -o-box-shadow: 0px 4px 8px #adadad;
    box-shadow: 0px 4px 8px #adadad;
  }
</style>

CSS遵循特定的规则来定义选择哪种HTML元素和如何设计元素。CSS规则包括两个主要部分:一个选择器和一个或多个声明。选择器就是典型的需要样式化的HTML元素。图1-6中,选择器是p。HTML中<p>元素代表一个段落。CSS规则中的第二个部分包括一个或多个声明,它们每一个都由一个属性和值构成。属性代表需要改变的样式属性。在我们的例子中,设置color属性为red。实际上,该CSS规则定义了段落中的所有文本颜色是红色的。

图1-6 CSS语法

我们使用p{color:red;},如图1-6所示。

下列示例中CSS规则包括多个声明。声明总是使用花括号括起来,每个声明以分号结束。此外,属性和值之间使用冒号。在这个特殊例子中,使用了两个定义:一个是段落的颜色,另一个是段落的文本对齐方式。请注意声明是通过分号进行分割的。

p {color:red; text-align:center}

CSS注释用来解释代码,你应该养成和任何其他编程语言中一样为CSS代码进行注释的习惯,且注释通常会被浏览器忽略。注释以斜线后跟一个星号开始,以星号后面跟斜线结束,其中的所有内容都是注释,将会被忽略。

/*
h1 {font-size:200%;}
h2 {font-size:140%;}
h3 {font-size:110%;}
*/

此外,为特定的HTML元素指定选择器,你可以使用id选择器来为任何与id选择器匹配的任意HTML元素的id值来定义样式。id选择器在CSS中是通过井号(#)后面跟id值定义的。

比如,在下列示例代码中,你看见三个id选择器:rightPanelleftPanelmap。在ArcGIS API for JavaScript应用程序中,总是会有一个map。当你定义<div>标签来作为map的容器时,定义一个id选择器,并通常赋值成map。在这种情况下,我们使用CSS来为地图定义多种样式,包括5像素的间距及特定颜色的实心样式边框和边框的弧度,如图1-7所示。

#rightPanel {
    background-color:white;
    color:#3f3f3f;
    border: solid 2px #224a54;
    width:20%;
}
#leftPanel {
    margin: 5px;
    padding :2px;
    background-color:white;
    color:#3f3f3f;
    border:solid 2px #224a54;
    width:20%;
}
#map {
    margin:5px;
    border: solid 4px #224a54;
    -mox-border-radius:4px;
}

图1-7 地图CSS样式说明

不同于id选择器专门为单个元素设置样式,类选择器可以为一组元素指定样式,它们都有相同的HTML类属性。类选择器通过.后面跟类名字来定义。你也可以指定受影响的样式只有特定的HTML元素和专门的类。下列代码显示了这两种情况下的例子。

.center {text-align:center;}
p.center {text-align:center;}

你的HTML代码可以用下列方式引用类选择器。

<p class="center">This is a paragraph</p>

有三种方式可以将CSS插入到你的应用程序中:行内样式、内嵌样式和链接样式。

第一种定义HTML元素的CSS规则方法是使用行内样式。但是我们不推荐使用这种方式,因为它和呈现层混杂在一起很难维护。只有在需要定义一组有限范围内CSS规则的情况下,才选择这种方式。使用行内样式,仅需将style属性放置在指定的HTML标签内部。

<p style="color:sienna;margin-left:20px">This is a paragraph.</p>

内嵌样式将所有的CSS规则应用到指定的Web页面中。只有那个专门页面中的HTML元素才能访问到样式规则。这里所有的CSS规则都定义在<head>标签之间并且包裹在<style>标签内,如下列代码所示。

<head>
    <style type="text/css">
        hr { color:sienna; }
        p { margin-left:20px; }
        body { background-image:url("images/back40.gif"); }
    </style>
</head>

链接样式就是一个简单的包括了CSS规则并保存成一个后缀名为.css的文本文件。通过使用HTML中的<link>标签可以将该文件链接到所有需要引用样式的Web页面中。这是一种用于将样式与主要的Web页面进行分离的常用方法。使用单独的链接样式能让我们拥有改变整个网站外观的能力。

现在让我们将重点放在级联样式表的级联部分上。你已知道,样式可以定义为链接样式、内嵌样式和行内样式。还有第四种样式我们没有讨论到,那就是浏览器默认样式,但这是你无法控制的。在CSS中,行内样式拥有最高权限,也就是说它将覆盖内嵌样式和链接样式或者浏览器样式。假如没有定义行内样式,内嵌样式中的任何样式规则将会优先于链接样式中定义的规则。这里需要说明的是,如果一个链接样式的引用放置在HTML<head>内嵌样式之后,链接样式将会覆盖内嵌样式。

是不是太多而难以记住?只要记住,底层的样式规则将覆盖样式规则层次结构中较高的即可,如图1-8所示。

图1-8 CSS优先权重(从下向上,优先级依次降低)

这些都是你需要理解的一些CSS基本概念。你可以使用CSS来定义几乎任何网页的样式,包括背景、文字、字体、链接、列表、图像、表格、地图和其他任何可见的对象。

你可能在想所有这些代码都放在什么位置,将所有的HTML、CSS和JavaScript代码放在同一个文件中或者将它们分割成单独的文件?对于非常简单的应用程序和示例来说,将所有代码放到一个后缀名为.html.htm的文件中也很常见。在这种情况下,CSS和JavaScript代码放置在HTML页面的<head>部分。然而,首选方式是使用代码栈创建应用程序来分离内容和行为的表现形式。应用程序的用户界面应该驻留在一个只包含用于定义应用程序部分的内容以及任何CSS(呈现)或JavaScript(行为)的HTML页面中。最终的结果是一个HTML页面和一个或多个CSS和JavaScript文件。这将形成一个图1-9所示的文件夹结构,里面包括一个名为index.html的文件和几个包括CSS、JavaScript和其他资源(比如图像)的文件夹。cssjs文件夹将包含一个或多个文件。

图1-9 网页构成

CSS文件通过使用<link>标签链接到HTML页面中。如下列代码所示,你将看到如何通过使用<link>标签来引入CSS文件。链接CSS文件应该放在HTML页面的<head>标签内。

<!DOCTYPE html>

<html>
  <head>
    <title>GeoRanch Client Portal</title>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
    <link rel="stylesheet" href="bootstrap/css/bootstrap.css">
  </head>
  <body>
  </body>
</html>

如下列代码所示,JavaScript文件通过<script>标签引入到HTML页面中。这些<script>标签放置在Web页面的<head>标签内部,如下列ArcGISAPI参考引用的JavaScript代码或者靠近页面结束在</body>标签结束之前的creategeometries.js文件。推荐引入JavaScript文件到靠近</body>标签结束的地方,因为当浏览器下载JavaScript文件时,它们不会下载任何东西直到下载完成。这可以使它看起来像应用程序那样加载缓慢。

JavaScript类库中推荐在头部添加<script>标签,比如Dojo通过body中的HTML元素交互解析,这就是在头部加载ArcGIS API for JavaScript的原因。

<!DOCTYPE html>
<html>
  <head>
    <title>GeoRanch Client Portal</title>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <script src="http://js.arcgis.com/3.7/"></script>
  </head>
  <body>
    <script src="js/creategeometries.js"></script>
  </body>
</html>

通过将代码分成几个文件,允许代码完全分离,这样也就易于维护。

在我们开始详细讨论ArcGIS API for JavaScript之前,你需要理解一些基本的HTML、CSS和JavaScript概念。本章目的就在于此,但你仍需要继续学习与这些主题相关的其他内容。到目前为止,你尚需掌握的内容还有很多。

应用程序展示是通过开发代码中的HTML和CSS来定义的,而应用程序中的功能是通过JavaScript进行控制的。这些都是非常不同的技能集合,很多人只擅长其中的一个,对于其他的就未必擅长了。大多数应用程序开发人员将重点放在通过JavaScript开发应用程序的功能上,而把HTML和CSS留给了设计人员。然而,对所有这些主题的基本概念方面有良好的理解也是很重要的。在下一章中,我们将深入探讨ArcGIS API for JavaScript并开始学习如何创建地图对象、添加动态和切片地图服务图层到地图中。


通过前一章的学习,我们已经掌握了关于HTML、CSS和JavaScript的一些基础知识。接下来我们将正式开始学习如何去创建一些很好的GIS Web应用程序。在本章中,我们将会为大家介绍关于如何创建地图并在地图上添加图层形式信息的一些基础概念。

本章中将包含如下主题。

当学习一门新的编程语言或者应用程序编程接口(API)的时候,我们总要有一个起点。使用ArcGIS API for JavaScript创建Web地图应用程序亦是如此。你不仅需要理解一些基本的JavaScript概念,还需要掌握HTML、CSS,当然还包括建立在DojoJavaScript框架之上的ArcGIS API for JavaScript。这些知识一下摆在你面前确实有点多,所以在本章我将带领你创建一个为后续章节做铺垫的非常基础的应用程序。模仿是学习编程技巧的最佳方法,所以在本章中,你需要将自己看到的用代码写出来,同时我会给出一些解释说明,并在后面章节中将保存这些代码的详细描述。

为了让你对ArcGIS API for JavaScript有一个初步的了解,在本章中我们需要创建一个简单的地图应用程序,即创建一个地图,添加一些数据图层并提供一些基本的地图导航功能。

使用ArcGIS API for JavaScript创建任何Web地图应用程序都必须遵循一些基本的步骤。在本章中,因为你是第一次看到这里的每一步骤,后面的部分我们将用大篇幅来介绍它们。当你每次使用ArcGIS API for JavaScript创建一个新的应用程序时,都必须按照这些基本步骤来操作。刚开始创建一个应用程序时,你会认为这些步骤有一点陌生奇怪,但是渐渐地你会懂得它们是做什么的以及为什么它们是必需的。在后续每个应用程序中你可以将这些步骤理解成一个模板。

现在让我们开始吧!

在本书中,我们将在ArcGIS API for JavaScript沙盒中编写和测试代码。关于沙盒的介绍可以访问http://developers.arcgis.com/en/javascript/sandbox/sandbox.html,其网页加载显示的内容如图2-1所示。你可以在左侧面板中编写代码,然后单击Run按钮,右侧面板中将会显示结果。

图2-1 沙盒显示结果

使用ArcGIS API for JavaScript创建任何GIS地图应用程序,都需要遵循一些步骤。假如想让地图成为应用程序的一部分,那么就需要你按照这些步骤来执行。在阅读本书时,我很难想象你不按照这些步骤来做会遇到怎样糟糕的情况。简而言之,你需要遵循以下步骤。

1.创建页面HTML代码。

2.引用ArcGIS API for JavaScript和样式表。

3.加载模块。

4.确保DOM可用。

5.创建地图。

6.定义页面内容。

7.页面样式。

这里仅仅是一个必需步骤的简短描述,我们将在接下来的介绍中对每个步骤进行详细说明。

在前面章节中,你已经掌握了HTML、CSS和JavaScript的基础概念。现在我们就来将这些技术应用到实际开发示例中去。首先你需要创建一个简单的HTML文档作为最终的地图容器。当我们开始使用ArcGIS API for JavaScript沙盒时,这些步骤就已经为你准备好了。但是,我想让你花点时间去看这些代码,从而能更好地掌握这些概念。在沙盒的左侧面板中,你看到下列示例中加粗显示的代码是引用自Web页面中基本的HTML代码,当然这里也有一些其他的HTML和JavaScript代码,但是下列代码构成一个Web页面的基本组成部分。这段代码包括几个基本的标签,包括<html><head><title><body>等。

<!DOCTYPE html>
<html>
<head>
 <title>Create a Map</title>
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
 <meta name="viewport" content="initial-scale=1,maximum-scale=1,user- scalable=no">
  <link rel="stylesheet" href="http://js.arcgis.com/3.7/js/dojo/dijit/ themes/claro/claro.css">
  <link rel="stylesheet" href=" http://js.arcgis.com/3.7/js/esri/css/ esri.css">
  <style>
 html,body,#mapDiv{
 padding:0;
 margin:0;
 height:100%;
 }
 </style>

<script src="http://js.arcgis.com/3.7/"></script>
  <script>
    dojo.require("esri.map");

    function init(){
      var map = new esri.Map("#mapDiv",{
         center:[-56.049,38.485],
         zoom:3,
          basemap:"streets"
      });
    }
    dojo.ready(init);
    </script>

  </head>
 <body class="claro">
 <div id="mapDiv"></div>
 </body>
 </html>

使用ArcGIS API for JavaScript进行开发时,必须要添加样式和API引用。在沙盒中,下列几行代码已经添加到了<head>标签内部。

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

<script src="http://js.arcgis.com/3.7/"></script>

<script>标签加载的是ArcGIS API for JavaScript。在编写本章时,它的当前版本是3.7。当一个新版本的API发布的时候,你需要相应地修改这个数字。<link>标签加载的是esri.css这个ESRI工具和组件的特定样式。

你可以选择性地添加一种DojoDijit主题样式。ArcGIS API for JavaScript是直接建立在DojoJavaScript框架上的。Dojo包括Claro、Tundra、Soria和Nihilo这四个预先定义的主题,它们用于控制添加到应用程序中的用户界面工具的外观样式。下列代码示例引用了Claro主题样式。

<link rel="stylesheet" href="http://js.arcgis/com/3.7/js/dojo/dijit/themes/ claro/claro.css">

其他样式可以参考下列示例代码进行引用,当然你也可以不引用任何一种样式。但是假如你添加Dojo用户界面组件(Dijits),你就需要通过加载其中的一种样式来控制组件的外观。

<link rel="stylesheet" href="http://js.arcgis/com/3.7/js/dojo/dijit/themes/ tundra/tundra.css">
<link rel="stylesheet" href="http://js.arcgis/com/3.7/js/dojo/dijit/themes/ nihilo/nihilo.css">
<link rel="stylesheet" href="http://js.arcgis/com/3.7/js/dojo/dijit/themes/ soria/soria.css">

你可以使用网站www.dojotoolkit.org中提供的主题测试器来感受一下每一个主题是如何影响用户界面组件的。样式测试器的地址为htpp://archive.dojotoolkit.org/nightly/dojotoolkit/dijit/themes/themeTester.html,图2-2所示的是Dijit主题测试器的界面。

图2-2 Dijit主题测试器界面

<script>
    dojo.require("esri.map");

   function init(){
   var map = new esri.Map("mapDiv",{
   center:[-56.049,38.485],
   zoom:3,
   basemap:"streets"
   });
   }
 dojo.ready(init);
</script>

在创建地图对象之前,必须首先通过使用一个名为require()的函数来完成对地图资源的引用。

过时或者AMD Dojo

无论是使用过时的Dojo还是使用新的AMD,对于大多数开发者来说都是一件沮丧的事情。异步模型定义(AMD)是在1.7版本的Dojo中产生的。ArcGIS API for JavaScript3.4是使用新的AMD方式进行所有模块重写后的第一个版本。过时的遗产和AMD方式都可以使用,但是建议在编写任何一个新的应用程序时都使用新的AMD方式。在本书中,我们要遵守这个规定,但是我们还要意识到在3.4版本的API发布之前编写的应用程序和一些ESRI示例仍然是以老版的代码风格呈现的。

在Web页面中使用require()函数来导入资源时,ArcGIS API for JavaScript提供了很多种资源,其中包括esri/map这个在创建地图或者使用Geometry、Graphic和Symbols之前必须用到的资源。一旦提供了资源的引用,你就可以使用Map()构造函数来创建地图。下面是如何在沙盒中运行代码的要点。

<script>
  require(["esri/map","dojo/domReady!"],function(Map){
 
 });
 
</script>

当一个网页加载时,所有组成页面的HTML元素都被加载并且解析。这就是大家熟知的文档对象模型DOM),它能保证JavaScript不能访问到网页上的任何元素直至所有的网页元素都被加载完毕。假如你的JavaScript代码试图去访问一个还没有加载的网页元素,就很明显会报错。为了避免这种情况的发生,Dojo中有一个ready()函数,可以将其包括在require()函数中,它仅会在HTML元素和任何模块加载之后才会执行。

另一种方法是你可以使用dojo/domReady!插件去保证所有的HTML元素都被加载。在这个练习中我们将使用第二种方法。

在先前的代码当中,我们已经使用dojo/domReady!插件并且将其添加到了require()函数中。


虽然可以直接添加JavaScript代码到基本的HTML文件中,但是更好的办法是创建一个单独的JavaScript文件(后缀名为.js)。本书为了简单起见,大部分代码都是直接写在了HTML文件内,但是当应用程序变得庞大且复杂的时候,希望你遵循将JavaScript代码写在一个单独的文件中的原则。

创建一个新的Map地图是通过esri/map这个先前步骤中所引入模块中的Map类来实现的。在require()函数内部,使用构造函数来创建一个新的Map对象。Map对象的构造函数中接收两个参数,第一个是在Web页面上用于承载地图的<div>标签的引用,还有一个是可选参数,其作用是定义各种地图加载选项。这个可选项被定义成一个包括一系列键/值对的JSON对象。

可能最常见的选项是basemap,通过它你可以从ArcGIS.com中选择一个预先定义的basemap,包括:streetssatellitehybridtopograyoceansnational-geographicosmzoom选项用来定义地图初始缩放级别,它是一个整数对应一个预先定义的缩放范围等级。minZoommaxZoom选项分别定义地图最小和最大范围缩放等级。center选项定义初始显示地图时显示的中心点,这个点是一个Point对象,包括一个经度/纬度坐标值对。当向Map对象的构造函数中传递参数时,还有一些其他的额外选项。

首先,我们创建一个全局的变量map以及require()函数,添加下列加粗显示的代码行。

<script>
      var map;
 require(["esri/map", "dojo/domReady!"], function(Map) {
 });
</script>

添加下列加粗代码到require()函数中,这些代码是新的Map对象的构造函数。传递到该构造函数中的第一个参数是承载地图的<div>标签的ID引用,我们到现在还没有定义这个<div>标签,但是在下面步骤中很快就会定义。第二个传递到构造函数中的参数是一个JSON对象,包括地理坐标的可选项,如地图中心、缩放级别和topo基础地图。

basemap.require(["esri/map", "dojo/domReady!"], function(Map) {
  map = new Map("mapDiv", {
 basemap: "topo",
 center: [-122.45,37.75], // long, lat
 zoom: 13,
 sliderStyle: "small"
 });
});

最后的一个步骤是创建用来承载地图容器的HTML<div>标签,你需要为这个<div>标签分配一个唯一的ID编号,这样JavaScript代码就能引用到它。在沙盒中这个<div>标签已经创建好了,唯一标识符为mapDiv,如下列加粗代码行所示。另外,还需要为<body>标签定义一个类属性,它应该引用你引入的dojo样式表。在下列代码中,你可以看到<body>标签已经在沙盒中创建了并且完成了先前的两个步骤。

<body class="claro">
 <div id="mapDiv"></div>
</body>

你可以向<head>标签中添加样式信息来为Web网页定义各种样式。在这个例子中,样式已经在沙盒中为你创建好了,如下列代码所示。本例中的样式包括设置地图,以适应整个浏览器窗口。

<style>
    html, body, #mapDiv {
      padding:0;
      margin:0;
      height:100%;
    }
</style>

这个简单例子的完整代码应该是这样的。

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=7, IE=9, IE=10">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user- scalable=no">
    <title>Simple Map</title>
    <link rel="stylesheet" 
    href="http://js.arcgis.com/3.7/js/esri/css/ esri.css">
    <link rel="stylesheet" href="http://js.arcgis.com/3.7/js/dojo/dijit/ themes/claro/claro.css">
    <style>
      html, body, #map {
        height: 100%;
        width: 100%;
        margin: 0;
        padding: 0;
      } 
    </style>
    <script src="http://js.arcgis.com/3.7/"></script>
    <script>
      var map;

      require(["esri/map", "dojo/domReady!"], function(Map) {
        map = new Map("map", {
          basemap: "topo",
          center: [-122.45,37.75], // long, lat
          zoom: 13,
          sliderStyle: "small"
        });
      });
    </script>
  </head>

  <body class="claro">
    <div id="map"></div>
  </body>
</html>

通过单击Run按钮来运行代码,假如代码一切正常的话,你可以看到如图2-3所示的输出结果。

图2-3 使用ArcGIS API for JavaScript创建应用程序的运行结果

在前面的内容中,我们已经介绍了使用ArcGIS API for JavaScript创建每一个应用程序所需要遵循的步骤。你已经学会了如何创建一个初始化的JavaScript函数。初始化脚本的目的是为了创建地图、添加图层和执行任何让应用程序启动时必需的安装程序。在本节中创建一个地图是你需要完成的一个任务,我们还将更加详细地讲述已创建Map类实例中的各种选项。

在面向对象编程语言中,创建一个类的实例常常是通过构造函数来完成的。构造函数是一个函数,用于创建或初始化一个新的对象。在这种情况下,构造函数被用来创建一个新的Map对象。在初始化一个对象状态时构造函数通常有一个或多个参数。

Map构造函数有两个参数,包括承载地图的容器和各种地图选项。然而,在调用这个构造函数创建地图时,必须首先引入esri/map为地图提供资源。一旦提供了引用的资源,你就可以使用该构造函数去创建地图。<div>的ID是构造函数中必需的参数,它用于指定地图容器。另外,你还可以传递多个可控制地图多个方面的选项,包括basemap图层、初始地图中心显示、导航控制显示、在平移过程中的graphic显示、进度条控制、细节层次等。

让我们更详细地了解在map构造函数中这些选项是如何指定的。构造函数中第二个参数选项通常是封闭在花括号内的。这里定义了JSON对象的内容。在花括号内部,每个选项有一个指定的名字,然后是一个冒号,后面是控制这个选项的数据值。在需要提交多个选项的构造函数事件中,每个选项通过逗号进行分割。下列示例代码显示了选项是如何添加到Map构造函数中的。

var map = new Map("mapDiv", {
  center: [-56.049, 38.485],
  zoom: 3,
  basemap: "streets"
});

在这个例子中,我们定义地图坐标选项可让地图居中,还有一个缩放级别和一个streets地图图层。这些选项是通过缩进的花括号,并且通过逗号进行分割的。

一幅没有数据图层的地图就像一个画家的空白画板一样。添加到地图中的数据图层让其有意义并为分析奠定了基础。提供数据图层添加到地图中主要有两种类型的地图服务:动态地图服务图层和切片地图服务图层。

动态地图服务图层在运行时创建地图图片并引用地图服务,然后返回图片到应用程序中。这种类型的地图服务或许由一个或多个图层信息构成。图2-4所示为Demograhpics地图服务,它由九个不同的图层构成,分别从不同地理层次代表Demographic信息。

图2-4 Demographics地图服务

客户端应用程序显示将花费更多时间,因为它们必须是动态生成的,所以动态地图服务层服务比切片地图服务图层拥有更多功能。在动态地图服务图层中,你可以通过控制图层定义显示的特征,设置地图服务中各图层的可见性并定义图层的瞬时信息。例如,在前面的图中描述的Demographics地图服务图层,你可以选择在你的应用程序中只显示Census Block Group图层。这是一种通过动态地图服务图层提供的功能,而在切片地图服务图层中则没有这样的功能。

切片地图服务图层引用的是一个预先定义好的地图切片缓存而不是动态加载的图片。用最简单的方法来理解切片地图服务,就是将它认为是覆盖在地图表面的网格。网格中的每一个单元格同样大小,用来将地图分割成单独的图片文件,从而成为切片。单个的切片是服务器上存储的图像文件,当需要的时候根据地图范围和比例尺来检索。在不同的地图比例尺下,这个过程会重复执行。当地图在应用程序中显示时,虽然地图由很多单独的切片构成,但是它们看起来是无缝拼接的,如图2-5所示。

图2-5 切片图构成

这些切片或者缓存地图图层通常用作底图,包括影像图、街道图、地形图或者不常发生变化的数据图层。切片地图服务显示速度更快,因为每次运行时向地图发送一个请求而并无创建图片的开销。

操作图层常覆盖在切片地图上面,这些图层通常为动态图层。虽然它们在执行时慢一点,但是动态地图服务图层有着在运行时仍可以定义外观的优势。

使用ArcGIS APIforJavaScript中的图层类,可以引用宿主在ArcGIS Server和其他地图服务器中的地图服务。所有的图层类继承自Layer这个基类。由于Layer类没有构造函数,所以你不可以专门针对这个类来创建一个对象。你可以简单地通过继承自Layer的子类来定义属性、方法和事件。

如图2-6所示,DynamicMapServiceLayerTiledMapServiceLayerGraphicsLayer全部继承自Layer类。DynamicMapServiceLayerTiledMapServiceLayer也可以作为基类。DynamicMapServiceLayer是动态地图服务的基类,TiledMapServiceLayer是切片地图服务的基类。第3章“添加图形到地图”完全使用图形和GraphicsLayer,所以我们将在本书后面部分讨论这种类型的图层。LayerDynamicMapServiceLayerTiledMapServiceLayer都是基类,所以在应用程序中不可以从这些类中指定创建一个对象。

图2-6 Layer类

如前面部分提到的那样,切片地图服务图层引用预先定好的图片缓存切片拼接在一起显示一幅无缝的地图,它通常用作底图。

如图2-7所示,ArcGISTiledMapServiceLayer类使用在当引用ArcGIS Server暴露的切片(缓存)地图服务时。这种类型的对象使用已经缓存过的切片地图集合,所以性能得以改善。ArcGISTiledMapServiceLayer构造函数接收URL指针指向地图服务,以及一些允许为地图服务指定ID和控制其透明度与可见性的选项。

图2-7 TiledMapServiceLayer类

如下列示例代码,注意ArcGISTiledMapServiceLayer构造函数接收一个引用地图服务的参数。当一个图层的实例创建后,调用接收一个包含引用切片地图服务图层的变量到Map.addLayer()方法中并添加到地图上。

var basemap = new ArcGISTiledMapServiceLayer("http://server.arcgisonline. com/ArcGIS/rest/services/World_Topo_Map/MapServer");
map.addLayer(basemap);

ArcGISTiledMapServiceLayer主要用来快速显示缓存的地图数据。你还可以控制显示数据的层级。比如,你想展示广义的ArcGISTiledMapService的数据,当用户放大到0~6级别时显示州际公路和高速公路,一旦用户进一步放大就切换到更详细的ArcGISTiledMapService。你还可以控制添加到地图上的每个图层的透明度。

顾名思义,如图2-8所示,ArcGISDynamicMapService类用来动态创建ArcGIS Server地图服务。和ArcGISTiledMapServiceLayer一样,ArcGISDynamicMapServiceLayer的构造函数接收一个指向地图服务的URL和一些参数选项用来为服务分配一个ID、设置地图图片的透明度和图层初始可见性选项为true或者falseArcGISDynamicMapServiceLayer的类名有时有误导性。虽然看上去是引用一个单独的数据图层,但实际上不是。它指的是一个地图服务而不是一个数据图层。地图服务内部的单个图层可以通过setVisibleLayers()方法来打开或者关闭。

图2-8 DynamicMapServiceLayer类

创建一个ArcGISDynamicMapServiceLayer的实例和ArcGISTiledMapServiceLayer非常类似,下列示例代码说明了这一点。构造函数接收一个指向地图服务的URL参数。第二个参数定义了可选参数,用来控制透明度、可见性和图像参数。

var operationalLayer = new ArcGISDynamicMapServiceLayer("http://sampleserver1. arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Population_World/MapServer",{"opacity":0.5});
map.addLayer(operationalLayer);

如下列代码所示,将上面两行代码添加到ArcGIS API for JavaScript沙盒中。

<script>
  var map;
  require(["esri/map", "esri/layers/ArcGISDynamicMapServiceLayer", 
"dojo/domReady!"], function(Map, ArcGISDynamicMapServiceLayer) {
    map = new Map("mapDiv", {
      basemap: "topo",
      center: [-122.45,37.75], // long, lat
      zoom: 5,
      sliderStyle: "small"
    });
    var operationalLayer = new ArcGISDynamicMapServiceLayer("http://
sampleserver1.arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Population_World/MapServer",{"opacity":0.5});
 map.addLayer(operationalLayer);
  });
</script>

运行上面的代码可以看到动态图层添加到了地图上,如图2-9所示。

图2-9 DynamicMapServiceLayer运行示例

使用ArcGISDynamicMapServiceLayer实例可以执行多种操作。显然,你可以创建地图来显示服务中的数据,你还可以查询服务图层中的数据、通过层定义控制特征显示、控制单个图层的可见性、设置时间相关信息、导出地图为图片、控制背景透明度和进行更多操作。

addLayer()方法接收一个图层(ArcGISDynamicMapServiceLayer或者ArcGISTiledMapServiceLayer)的实例作为第一个参数,一个可选索引指示图层放置的位置。下列示例代码创建了一个新的ArcGISDynamicMapServiceLayer实例指向服务的URL。然后调用Map.addLayer()并传递图层的一个新的实例。服务中的图层现在在地图上可见。

var operationalLayer = new ArcGISDynamicMapServiceLayer("http://sampleserver1. arcgisonline.com/ArcGIS/rest/services/Demographics/ESRI_Population_World/MapServer");
map.addLayer(operationalLayer);

addLayer()方法接收图层对象数组并一次添加成功。

除了能够添加图层到地图外,还可以使用Map.removeLayer()或者Map.removeAllLayers()来从地图中移除某个或者所有图层。

可以使用setVisibleLayers()方法控制动态地图服务中单个图层的可见性。该方法仅适用于动态地图服务图层,对切片地图服务图层则不适用。该方法接收一个整型数组,对应地图服务中的数据图层索引编号。

这个数组是从0开始的,因此地图服务中的第一个图层占据位置0。如图2-10所示,Demographics地图服务中Demographics/ESRI_Census_USA占据索引0。

图2-10 Demographics服务中图层索引

因此,如果只想显示这个服务中的Census Block Points和Census Block Group图层的话,我们可以使用setVisibleLayers()方法,如下列代码所示。

var dynamicMapServiceLayer = new ArcGISDynamicMapServiceLayer("https://gis. sanantonio.gov/ArcGIS/rest/services/Demographics/MapServer");
dynamicMapServiceLayer.setVisibleLayers([1,2]);
map.addLayer(dynamicMapServiceLayer);

在ArcGISforDesktop中,可以使用定义表达式来限制数据图层特征的显示。一个定义表达式就是一个图层中针对行和列的简单SQL查询。仅满足查询条件的特征才会显示。如图2-11所示,假如只想显示人口大于100万的城市,表达式为POPULATION>1000000。ArcGIS API for JavaScript中包含setLayerDefinitions()方法接收适用于ArcGISDynamicMapServiceLayer来控制结果地图中特征显示的数组定义。下列示例代码展示了实现过程。

图2-11 表达式定义

首先创建一个可容纳多个where语句的数组,它可以作为每个图层的定义表达式。在这种情况下,我们定义了第1个和第6个图层。数组是从0开始的,所以数组中的第一个就在索引0,where子句放到数组并传递到setLayerDefinitions()方法中,ArcGIS Server然后仅加载每个图层中满足where子句的特征。

既然已掌握了一些关于地图和图层的知识,现在该学习如何在应用程序中控制地图导航了。在大多数情况下,用户需要能够通过平移和缩放特征来对地图进行导航操作。ArcGIS API for JavaScript提供一系列用户接口部件和工具栏,你可以用来允许用户通过使用缩放和平移特征来改变当前地图范围。地图导航还可以通过键盘和鼠标进行。除了这些用户接口部件和硬件接口外,地图导航还可以通过编程进行控制。

1.地图导航部件和工具栏

为应用程序提供地图导航控制功能的最简单的方式是添加各种部件和工具栏。当创建一个新地图和添加图层时,地图上已经包含了一个默认的缩放进度条。该进度条允许用户放大和缩小地图。缩放进度条如图2-12所示。让缩放进度条显示在地图中不需要你做任何的编程操作,默认它就是显示的。然而当创建一个Map对象实例时,如果有必要,你可以在应用程序中通过设置slider选项为false移除进度条。

图2-12 地图缩放进度条

{"slider":false,"nav":true,"opacity":0.5,"imageParameters":imageParameters}

你还可以添加平移按钮,当单击的时候地图会朝着箭头指向的方向平移。默认平移按钮不会出现在地图上。当创建Map对象时,你必须明确设定nav选项为true

{"nav":true,"opacity":0.5,"imageParameters":imageParameters}

如图2-13所示为地图平移选项。

图2-13 地图平移选项

ArcGISAPI for JavaScript还具备为应用程序添加多种类型的工具栏的能力,包括导航工具栏,如放大和缩小按钮、平移、全图、前一视图和后一视图。工具栏创建在后面章节会介绍到,所以我们会稍后讨论它。

图2-14 地图工具栏

2.使用鼠标和键盘进行地图导航

用户可以使用鼠标和键盘设备来控制地图导航。用户默认可以进行下面这些操作。

上面的选项可通过Map中的方法进行禁用。比如,要禁用滚轮缩放,你可以使用Map.disableScrollWheelZoom()方法。当地图加载后这些导航特征就可以移除掉。

3.获取和设置地图范围

我们要掌握的第一件事是获取和设置地图范围。应用程序中默认的初始地图范围是最后一次你在创建地图服务时保存的地图文档文件(.mxd)的范围。在某些情况下,这也许正是你需要的,但是如果需要设置默认外的地图范围的话,你也有其他选择。

一个可选参数是居中参数,可在Map对象的构造函数中定义。你可以使用这个可选参数结合缩放对象来设置地图范围。如下列代码,我们定义了地图的中心坐标并设置了缩放级别为3。

var map = new Map("mapDiv", {
        center: [-56.049, 38.485],
        zoom: 3,
        basemap: "streets"
      });

初始地图范围并不是一个必需参数,因此假如你忽略了该信息,地图会使用默认范围。下列代码显示的是仅指定了地图容器的ID。

var map = new Map("map");

当一个Map对象创建后,我们还可以传递一个Extent对象到Map.setExtent()方法中来改变范围,如下列代码所示。

var extent = new Extent(-95.271, 38.933, -95.228, 38.976);
map.setExtent(extent);

另外,你可以单独设置Extent的属性,如下列代码所示。

var extent = new Extent();
extent.xmin = -95.271;
extent.ymin = 38.933;
extent.xmax = -95.228;
extent.ymax = 38.976;
map.setExtent(extent);

有时应用程序中使用多地图服务,在这种情况下设置初始地图范围,无论是通过地图构造函数还是通过某个服务的Map.fullExtent()方法都可以完成设置。例如,常见的有提供包含航空影像的基础图层和包含本地操作数据源的服务结合的地图服务。

map = new Map("mapDiv", {extent:esri.geometry.geographicToWebMercator (myService2.fullExtent) });

当前范围通过Map.extent属性或者onExtentChange事件获取到。请注意Map.setExtent属性是只读的,因此不可能通过这个属性来设置地图范围。

在编程世界里,事件是发生在应用程序中的动作。通常,这些事件通过终端用户触发,包括鼠标单击、鼠标拖拽和键盘动作,但是它还包括数据的发送和接收、组件修改和其他操作。

ArcGIS API for JavaScript是一个异步的API,遵循应用程序注册(发布)事件的监听(用户)中的发布/订阅模式。图2-15说明了该过程。监听器负责监控应用程序中的事件,然后触发一个处理函数来响应事件。多个事件可以注册到同一个监听器中。dojo中的on()方法就是这样的一个事件处理程序。

图2-15 API异步处理过程

你可能还记得,ArcGIS ServerJavaScriptAPI建立在Dojo之上。使用Dojo,事件通过dojo的on()方法注册给处理程序。该方法接收三个参数,仔细观察图2-16,你会对事件注册有更好的理解。

图2-16 事件注册

我们调用带参数的on()方法,参数包括mapclickdisplayCoordinates。前面两个参数代表对象和我们需要注册的事件。在这种情况下,意味着我们正在为Map对象注册click事件。在地图范围内,每当用户单击鼠标就会触发此事件。最后一个参数displayCoordinates代表事件的监听器。因此,每当Map对象的click事件触发时,将会触发displayCoordinates函数,它将运行并报告地图当前范围。虽然事件和注册的处理取决于环境的变化,但是注册的方法是一样的。

每次事件发生时,Event对象将产生。该Event对象包括额外的事件信息,比如鼠标按钮被单击或者键盘某个按键被按下。这个对象会自动传递到事件处理程序中检查。如下列代码所示,你可以看到Event对象作为一个参数传递到了处理程序中。这是一个动态对象,它的属性也会根据被触发的事件类型而发生变化。

function addPoint(evt) {
    alert(evt.mapPoint.x, evt.mapPoint.y);
}

API中不同对象有着不同的事件。但是,你要牢记不要用监听器来注册每一个事件。只有那些应用程序中需要的事件才需要注册。当一个事件没有使用监听器进行注册时,该事件会被忽略。

Map对象包含多种不同响应事件,包括各种鼠标事件、范围改变事件、底图改变事件、键盘事件、图层事件、平移和缩放事件以及更多其他事件。应用程序中可以响应任意这些事件。在接下来的章节中,我们将学习其他对象可用的事件。

在不需要的时候,从处理函数中断开事件是一个好的编程习惯。这通常在当用户从页面导航离开或者关闭浏览器窗口时完成。下列代码显示了如何简单地通过调用remove()方法完成移除单击事件。

var mapClickEvent = on(myMap, "click", displayCoordinates);
mapClickEvent.remove();

我们已经在本章中涵盖了很多基础内容。所有使用ArcGIS API for JavaScript创建的应用程序需要一组特定的步骤,我们称之为样板代码,它包括定义引用API和样式表、加载模块、创建初始化函数和一些其他步骤。在初始化函数中,将会创建一个地图、添加各种图层和在使用应用程序之前需要执行其他的安装操作。在本章中,我们学会了如何执行这些任务。

此外,我们学习了多种可以添加到地图上的图层,包括切片地图服务图层和动态地图服务图层。切片地图服务图层是预先创建的并且缓存在服务器上,因此常用来作为应用程序中的底图。动态服务图层是每次一个请求发生后创建的,所以可能需要更长的时间才能产生。然而,动态地图服务图层能用来执行多种类型的操作,包括查询、设置定义表达式和更多其他操作。

另外,我们已经学会了通过编程的方式来控制地图范围。最后,我们介绍了事件这个主题,学会了事件如何与事件处理程序关联,其实就是一个简单的JavaScript函数,它运行在一个特殊事件被触发的任何时机。在下一章中,我们将密切关注如何添加图形到应用程序中。


相关图书

基于ArcGIS的Python编程秘笈(第2版)
基于ArcGIS的Python编程秘笈(第2版)
ArcGIS 10.1超级学习手册
ArcGIS 10.1超级学习手册
面向ArcGIS的Python脚本编程
面向ArcGIS的Python脚本编程
精通ArcGIS Server 应用与开发
精通ArcGIS Server 应用与开发
ArcGIS Engine  地理信息系统开发从入门到精通(第二版)
ArcGIS Engine 地理信息系统开发从入门到精通(第二版)

相关文章

相关课程