一个使用Ruby on Rails开发LBS网站的简单实例

 

一个使用Ruby on Rails开发LBS网站的简单实例

cheungmine

2011-7

这几天一直在学习使用Ruby on Rails(RoR),想建立一个功能全面一点的LBS(Location Based Service)网站。但是对于我这个RoR的初学者(仅有几天时间)来说,毕竟太复杂了。因此本文试图简化原来的设计思路,抛弃一切权限管理,仅仅对数据表中的坐标位置进行插入和更新。也就是,使用表单提交用户坐标位置信息,地图页面定时刷新获取这些信息并显示在地图上。通过这个例子,来熟悉RoR的编程,熟悉ArcGIS Online Map。掌握Ajax在RoR中的一般用法(RJS)。

关键词:Ruby, RoR, MySQL, LBS, Ajax, RJS, ArcGIS Online Map, Dojo

0 安装RubyOnRails

Windows环境下一键安装RubyOnRails开发环境

1)直接点击链接下载:

http://rubyforge.org/frs/download.php/29867/InstantRails-2.0-win.zip

2)或者进入下载页面,选择要安装的版本:http://rubyforge.org/frs/?group_id=904

3)在Windows下安装InstantRails-2.0-win, 解压到无空格的英文路径下即可,如C:\。然后双击C:\InstantRails-2.0-win\InstantRails.exe文件即可启动InstantRails。

4)因为我总是喜欢使用MySQL,因此要手动把文件C:\InstantRails-2.0-win\mysql\bin\libmySQL.dll复制到目录C:\InstantRails-2.0-win\ruby\bin\。这个应该算InstantRails安装包的一个小缺陷吧。

2)开发用到的工具软件

1 创建Rails项目

从InstantRails进入Ruby命令行,输入清单1的命令:

图1:打开Ruby命令行

清单1:创建项目gis

  1. C:\InstantRails-2.0-win\rails_apps>rails -d mysql gis  
  2. cd gis  
  3. ruby script/server  
第1行创建项目,第2行切换到项目中,第3行启动gis服务。点击浏览 http://127.0.0.1:3000/就可以看到网站正确地建立了,如图2:

图2:RoR默认网站

2 创建数据库

从InstantRails进入Ruby命令行:

清单2:创建项目数据库

  1. cd gis  
  2. gis>mysql -u root –p  
  3. mysql> create database gis_dev;  
  4. mysql> create database gis_test;  
  5. mysql> create database gis;  
  6. mysql> exit;  
  7. gis>  
提示Enter Password:时,直接回车。 编辑\rails_apps\gis\config\database.yml文件,修改数据库名:gis_development=>gis_dev,gis_production=>gis。

3 导入数据表(locations)

从InstantRails->Configure->Database (via PhpMyAdmin),使用以下脚本创建gis_dev中的数据表。

清单3:创建gis_dev数据库表locations

  1. drop table if exists locations;  
  2. create table locations (  
  3.   id int not null auto_increment,  
  4.   user_id int not null,  
  5.   recv_time timestamp default current_timestamp not null,  
  6.   x_long decimal(12,7) null,  
  7.   y_lat decimal(12,7) null,  
  8.   z_elev decimal(12,3) null,  
  9.   velocity decimal(10,0) null,  
  10.   accel decimal(10,0) null,  
  11.   direction decimal(10,4) null,  
  12.   pitch decimal(10,4) null,  
  13.   roll decimal(10,4) null,  
  14.   battery decimal(3,0) null,  
  15.   confidence decimal(3,0) null,  
  16.   message varchar(200) null,  
  17.   primary key (id)  
  18. );  
说明:
    user_id:用户id
    recv_time:收到信息的时间,这是个数据库自动填充时间的字段
    x_long:经度deg
    y_lat:纬度deg
    z_elev:高度m
    velocity:速度m/s
    accel:加速度
    direction:方向角度
    pitch: 俯仰角度
    roll:倾斜角度
    battery:电池电量0-100
    confidence:信号强度0-100,似乎用signal更好一些
    message:短消息,提供呼叫信息功能
选择数据库gis_dev,在选择SQL标签页,将上面的SQL脚本粘帖到框中,最后按右下角的【执行】按钮。如图3所示:


图3:使用PhpMyAdmin创建数据表

4 生成location模型

进入Ruby命令行,切换到gis目录,输入下面的命令,在一行中输入:
清单4:创建locations Model
  1. ruby script/generate scaffold Location user_id:int recv_time:datetime x_long:decimal y_lat:decimal z_elev:decimal  velocity:decimal accel:decimal direction:decimal pitch:decimal roll:decimal battery:decimal confidence:decimal message:string  
访问地址:http://localhost:3000/locations 应该看到正确的网页。如果上面的脚本执行的结果不正确,我们进入目录,删除它的执行结果,也就是删除下面的文件或目录:
    C:\InstantRails-2.0-win\rails_apps\gis\app\controllers\locations_controller.rb
    ...\gis\app\models\location.rb
    ...\gis\app\views\locations\
然后重新执行命令。
现在我们可以通过http://localhost:3000/locations/new创建新的location:

图4:创建location的界面

5 建立网站首页

清单5:创建home/index
  1. $ ruby script/generate controller home index  
  2. $ rm public/index.html  
$ 代表命令行当前目录提示符:C:\InstantRails-2.0-win\rails_apps\gis>,下同。这样就新建了一个名为home的controller和该controller下的名为index的action。第2行删除默认的首页。然后加入指定的默认首页:
在 config/routes.rb 文件中,将 # map.root :controller => "welcome" 改为:
    map.root :controller => "home"
默认首页文件变为:...\gis\app\views\home\index.html.erb。访问地址为:
http://localhost:3000/

我们用预先建好的使用了ArcGIS Online Map的网页替换掉\home\index.html.erb,替换之后的index.html.erb见清单6。

清单6:网站首页文件index.html.erb

[html]  view plain copy print ?
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">  
  2. <html>   
  3. <head>  
  4.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
  5.     <meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" />  
  6.     <!--The viewport meta tag is used to improve the presentation and behavior of the samples on iOS devices-->  
  7.     <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>  
  8.     <title>LBS Test Map</title>  
  9.     <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.4/js/dojo/dijit/themes/claro/claro.css">  
  10.     <style type="text/css">  
  11.         html,body {  
  12.             height:100%;  
  13.             width:100%;  
  14.             margin:0;  
  15.         }  
  16.         body {  
  17.             background-color:#FFF;  
  18.             overflow:hidden;  
  19.             font-family:"Trebuchet MS";  
  20.         }  
  21.         #mainWindow {  
  22.             width:100%;  
  23.             height:100%;  
  24.             margin:0px;  
  25.             padding:0;  
  26.         }  
  27.         #header {  
  28.             border:solid 0px #FFF;  
  29.             border-bottom:1px solid #AEAEAE;  
  30.             background-color:#EEF2FB;  
  31.             color:#CD853F;  
  32.             font-size:10pt;  
  33.             text-align:center;  
  34.             height:80px;  
  35.             margin:0px;  
  36.             padding:0;            
  37.         }  
  38.         #subheader {  
  39.             font-size:small;  
  40.             color:#CD853F;  
  41.         }  
  42.         #rightPane {  
  43.             background-color:#FFF;  
  44.             border:none;  
  45.             width:300px;  
  46.             overflow:hidden;  
  47.             margin:0px;  
  48.             padding:0;  
  49.         }  
  50.         #mapDiv {  
  51.             background-color:#FFF;  
  52.             border:solid 1px #AEAEAE;  
  53.             margin:0px;  
  54.             padding:0;  
  55.         }  
  56.         #measurementPaneDiv {  
  57.             background-color:#FFF;  
  58.             border:solid 1px #B8B8B8;  
  59.             height:130px;  
  60.             overflow:hidden;  
  61.             margin:0px;  
  62.             padding:0;  
  63.         }  
  64.         #measurementDiv {  
  65.             background-color:#FFF;  
  66.             font-size:10pt;  
  67.             height:100%;  
  68.             overflow:hidden;  
  69.             margin:0px;  
  70.             padding:0;  
  71.         }          
  72.     </style>  
  73.     <script type="text/javascript">  
  74.         var djConfig = {  
  75.             parseOnLoad: true  
  76.         };  
  77.     </script>  
  78.     <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.4">  
  79.     </script>  
  80.     <script type="text/javascript">  
  81.         dojo.require("dijit.dijit"); // optimize: load dijit layer  
  82.         dojo.require("dijit.layout.BorderContainer");  
  83.         dojo.require("dijit.layout.ContentPane");  
  84.         dojo.require("esri.map");  
  85.         dojo.require("esri.dijit.Measurement");          
  86.         dojo.require("esri.dijit.Scalebar");  
  87.         dojo.require("esri.toolbars.draw");  
  88.         dojo.require("esri.dijit.OverviewMap");  
  89.   
  90.         var map, spatialRef, initExtent;  
  91.       
  92.         // init on load  
  93.         function initGCS_WGS_1984()  
  94.         {  
  95.             // 4326 = GCS_WGS_1984  
  96.             spatialRef = new esri.SpatialReference({wkid:4326});  
  97.               
  98.             // china extent  
  99.             initExtent = new esri.geometry.Extent(65, 9, 145, 55, spatialRef);  
  100.             map = new esri.Map("mapDiv");  
  101.             map.setExtent(initExtent);  
  102.               
  103.             dojo.connect(map, 'onLoad', function(map) {  
  104.                     var scalebar = new esri.dijit.Scalebar({map: map, scalebarUnit: "metric"});  
  105.   
  106.                     dojo.connect(dijit.byId('mapDiv'), 'resize', resizeMap);                          
  107.                     initToolbar(map);  
  108.                       
  109.                     // add the overview map   
  110.                     var overviewMapDijit = new esri.dijit.OverviewMap({map: map, visible:false});  
  111.                     overviewMapDijit.startup();  
  112.                 }  
  113.             );  
  114.                   
  115.             var basemapUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer";  
  116.             var basemap = new esri.layers.ArcGISTiledMapServiceLayer(basemapUrl);  
  117.             map.addLayer(basemap);  
  118.         }  
  119.           
  120.         // init on load  
  121.         function initWGS_1984_Web_Mercator_Auxiliary_Sphere() {  
  122.             // 102100 = WGS_1984_Web_Mercator_Auxiliary_Sphere  
  123.             spatialRef = new esri.SpatialReference({"wkid": 102100});  
  124.               
  125.             // china extent  
  126.             initExtent = new esri.geometry.Extent({  
  127.                             "xmin":-32971876.5210848,  
  128.                             "ymin":2044843.3806844242,  
  129.                             "xmax":-23921732.37212246,  
  130.                             "ymax":7127600.013534156,  
  131.                             "spatialReference":{"wkid":102100}  
  132.                         });  
  133.               
  134.             map = new esri.Map("mapDiv", {extent:initExtent, wrapAround180:true});  
  135.               
  136.             dojo.connect(map, 'onLoad', function(map) {  
  137.                     var scalebar = new esri.dijit.Scalebar({map: map, scalebarUnit: "metric"});  
  138.                     dojo.connect(dijit.byId('mapDiv'), 'resize', resizeMap);                          
  139.                     initToolbar(map);  
  140.                       
  141.                     // add the overview map   
  142.                     var overviewMapDijit = new esri.dijit.OverviewMap({map: map, visible:false});  
  143.                     overviewMapDijit.startup();  
  144.                 }  
  145.             );  
  146.               
  147.             var basemapUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer";  
  148.             var basemap = new esri.layers.ArcGISTiledMapServiceLayer(basemapUrl);  
  149.             map.addLayer(basemap);  
  150.               
  151.             var referenceUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer";  
  152.             var referenceLayer = new esri.layers.ArcGISTiledMapServiceLayer(referenceUrl);  
  153.             map.addLayer(referenceLayer);             
  154.         }  
  155.   
  156.         // resize map  
  157.         function resizeMap() {  
  158.             var resizeTimer;  
  159.             clearTimeout(resizeTimer);            
  160.             resizeTimer =   
  161.                 setTimeout(  
  162.                     function(){map.resize(); map.reposition();}, 500  
  163.                 );  
  164.         }  
  165.           
  166.         function initToolbar(map) {  
  167.             //define a new line symbol and point symbol to use for measure tools  
  168.             var pms = new esri.symbol.PictureMarkerSymbol("images/flag.png", 24, 24);  
  169.             pms.setOffset(9,11);  
  170.             var sls = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_DOT,  
  171.                         new dojo.Color([255,0,0,.55]), 4);  
  172.                           
  173.             var measurement = new esri.dijit.Measurement({  
  174.                     map: map,  
  175.                     lineSymbol:sls,  
  176.                     pointSymbol:pms  
  177.                 },   
  178.                 dojo.byId('measurementDiv')  
  179.             );  
  180.               
  181.             measurement.startup();     
  182.             measurement.setTool("area", true);  
  183.         }  
  184.         
  185.         // show map on load   
  186.         dojo.addOnLoad(initGCS_WGS_1984);      
  187.         // dojo.addOnLoad(initWGS_1984_Web_Mercator_Auxiliary_Sphere);    
  188.     </script>  
  189. </head>  
  190. <body class="claro">  
  191.     <div id="mainWindow" dojotype="dijit.layout.BorderContainer" design="headline" gutters="false">  
  192.         <div id="header" dojotype="dijit.layout.ContentPane" region="top">  
  193.             <h1>A Test for RoR with ArcGIS Online Map</h1>  
  194.         </div>  
  195.         <!-- header -->  
  196.   
  197.         <div id="mapDiv" dojotype="dijit.layout.ContentPane" region="center">  
  198.         </div>  
  199.         <!-- mapDiv -->  
  200.           
  201.         <div id="rightPane" dojotype="dijit.layout.BorderContainer" region="right" gutters="false">  
  202.             <div id="admin_div" dojotype="dijit.layout.ContentPane" style="height:100%;" region="center">  
  203.             </div>  
  204.             <!-- admin_div -->  
  205.               
  206.             <div id="measurementPaneDiv" dojotype="dijit.layout.ContentPane" region="bottom">  
  207.                 <div id="measurementDiv" style="height:100%;"></div>  
  208.             </div>  
  209.             <!-- measurementPaneDiv -->  
  210.         </div>  
  211.         <!-- rightPane -->  
  212.     </div>  
  213.     <!-- mainWindow -->  
  214. </body>  
  215. </html>  
本文把HTML代码、css、js放在一起,是为了说明上的方便,实际当中应分开放置。关于如何使用ArcGIS Online Map和ArcGIS JSAPI编程请参考下面的网址:

   http://help.arcgis.com/en/webapi/javascript/arcgis/help/jsapi_start.htm
此时我们再浏览http://localhost:3000/,显示如图5所示:

图5:网站(gis)的首页

6 用RJS查询locations

我的设想是设置一个定时器,不断地查询locations表,把获得的记录显示右边的空白处(<div id="admin_div" ></div>),同时把坐标点显示在地图(map)上。当我们访问http://localhost:3000/locations,会显示locations数据表的全部信息,因此我们就想办法把这个表显示在admin_div处,这就需要引入Ajax,或者称为RJS(Ruby-generated JavaScript)的东西。请参考我转载的一篇文章(RubyOnRails with Ajax),那里面详细讨论了RJS技术的实现原理和方法。

6.1 添加定时器查询数据库

为此我们首先添加一个链接到清单6中(\home\index.html.erb),当用户点击这个链接,admin_div就显示查询的结果。添加链接之后的代码如下:

清单7:修改index.html.erb,红色粗体的部分是我新增的代码

  1. <div id="header" dojotype="dijit.layout.ContentPane" region="top">  
  2.     Click this link to show the current   
  3.     <%= link_to_remote "locations",   
  4.     :update => 'admin_div',   
  5.     :url => {:controller=>"locations", :action =>"list_by"} %>.  
  6. </div>  
  7. <!-- header -->  
上面清单7代码中,:url => {:controller=>"locations", :action =>"list_by"}指明链接的位置:controller和action。我们知道在locations controller中并没有list_by这个action,我手动把这个list_by添加到locations_controller.rb中,不要修改其他任何部分,见清单8:

清单8:给locations_controller.rb添加list_by,红色粗体的部分是我新增的代码
[ruby]  view plain copy print ?
  1. class LocationsController < ApplicationController  
  2.   # GET /locations  
  3.   # GET /locations.xml  
  4.   def index  
  5.     @locations = Location.find(:all)  
  6.   
  7.     respond_to do |format|  
  8.       format.html # index.html.erb  
  9.       format.xml  { render :xml => @locations }  
  10.     end  
  11.   end  
  12.    
  13.   # add by me  
  14.   def list_by  
  15.     redirect_to :action => "index"  
  16.   end  

另外为了支持RJS,我们还需要把<%= javascript_include_tag :defaults %>添加到index.html.erb中:

清单9:添加RJS声明

  1. ...  
  2. </style>  
  3. <%= javascript_include_tag :defaults %>  
  4. <script type="text/javascript">  
  5. ...  
现在我们浏览http://localhost:3000/并点击 locations链接后,界面显示如下:

图6:增加了RJS后的首页

到目前为止,locations链接是您见到的惟一触发器。Ajax 还有许多其他的可用武器,一些由用户驱动,而另一些由程序事件驱动,如时钟。它是一个像闹钟一样并不需要用户干预的东西。可以用 Ajax 的 periodically_call_remote 方法定期更新时钟。更改 index.html.erb 代码如清单10(仅仅修改红色黑体部分):

清单10:修改index.html.erb,增加periodically_call_remote

[ruby]  view plain copy print ?
  1. <div id="header" dojotype="dijit.layout.ContentPane" region="top">  
  2.     <h1>A Test for RoR with ArcGIS Online Map</h1>  
  3.     <%= periodically_call_remote :update => 'admin_div',     
  4.                      :url => {:controller=>"locations":action =>"list_by"},    
  5.                      :frequency => 3.0 %>  
  6. </div>  
  7. <!-- header -->  
重新浏览http://localhost:3000/,现在发现admin_div被每3秒自动更新一次。此时我们打开一个新的浏览器并定位到http://localhost:3000/locations/new,创建一个新的location,可以在http://localhost:3000/页面看到Listing locations发生了变化,我们新增加的记录被添加到了底部:

图7:自动更新Listing locations

接下来的工作主要是页面的重构和美化。说实在的,这的确耗去了我很多时间。重构之后的页面改变了某些div的id,对部分网页代码也做了调整。最终的成果就是看起来如图8的样子:

图8:最终的gis主页

6.2 为定时器添加启动(Start Monitor)和暂停(StopMonitor)的方法

我们设想用户可以控制periodically_call_remote定时器的启动和停止。因此需要修改一下Ruby代码。修改后的代码如下:

清单11:控制periodically_call_remote定时器的启动和停止代码

[ruby]  view plain copy print ?
  1. <head>  
  2.     ......  
  3.     <%= javascript_include_tag :defaults %>  
  4.     <script type="text/javascript">  
  5.     ......  
  6.         var myMonitor = true;  
  7.         var myUpdater = null;  
  8.           
  9.         PeriodicalExecuter.prototype.resume = function(){  
  10.             if(!this.timer)  
  11.                 this.registerCallback();  
  12.         };  
  13.           
  14.         function startMonitor() {  
  15.             if (myUpdater != null)  
  16.             {  
  17.                 myUpdater.resume();  
  18.             }  
  19.         }  
  20.           
  21.         function stopMonitor() {  
  22.             if (myUpdater != null)  
  23.             {  
  24.                 myUpdater.stop();  
  25.             }  
  26.         }  
  27.     </script>  
  28. </head>  
  29. <body class="claro">  
  30.     <%= periodically_call_remote(  
  31.         :variable => "myUpdater",  
  32.         :condition => "myMonitor == true",  
  33.         :update => "locations_div",  
  34.         :url => {:controller=>"locations":action =>"list_by"},  
  35.                 :frequency => 5,  
  36.         :complete => "new Effect.Highlight('locations_div');refreshLocations(dojo.byId('tb_users'));") %>  
  37.           
  38.     <div id="mainWindow" dojotype="dijit.layout.BorderContainer" design="headline" gutters="false">  
  39.         ......  
  40.             <div id="locations_div" dojotype="dijit.layout.ContentPane" region="center">  
  41.             </div>  
  42.             <!-- locations_div -->  
  43.         ......  
  44.     </div>  
  45. </body>  

:variable => "myUpdater", 指明new PeriodicalExecuter返回变量名。
:condition => "myMonitor == true", 指明触发器回调函数运行的条件。
:update => "locations_div", 指明要更新的div id。就是上文的(admin_div),我改了名字。
:url => {:controller=>"locations", :action =>"list_by"}, 指明控制器和反应器名称。
:frequency => 5, 指定定时器间隔5秒
:complete => "...." 指明链接加载完毕onComplete执行的代码,我们的JavsScript代码可以放在这里。

我增加了下面的代码:
    PeriodicalExecuter.prototype.resume = function(){
        if(!this.timer)
            this.registerCallback();
    };
因为PeriodicalExecuter是...\gis\public\javascripts\prototype.js中的JS对象。PeriodicalExecuter只有stop方法,为此我们需要增加了启动定时器的重启方法resume()。
比较清单11中蓝色的代码和运行后查看浏览器源代码中的显示(我做了排版编辑):

清单12:查看浏览器源代码

[ruby]  view plain copy print ?
  1. myUpdater =   
  2.     new PeriodicalExecuter(  
  3.         function(){  
  4.             if (myMonitor == true) {  
  5.                 new Ajax.Updater(  
  6.                     'locations_div',   
  7.                     '/locations/list_by',  
  8.                     {  
  9.                         asynchronous:true,   
  10.                         evalScripts:true,   
  11.                         onComplete:function(request) {  
  12.                             new Effect.Highlight('locations_div');  
  13.                             refreshLocations(dojo.byId('tb_users'));  
  14.                         },   
  15.                         parameters:'authenticity_token=' + encodeURIComponent('314268a80fbdca6f758e7bd120507c12a10c4698')  
  16.                     }  
  17.                 );  
  18.             }  
  19.         },  
  20.         5  
  21.     );  
只要能操作 PeriodicalExecuter的实例myUpdater和控制boolean变量myMonitor就可以 控制periodically_call_remote定时器。为此我们需要修改Ruby产生的默认代码,这个过程称为override。默认的代码没有返回myUpdater,因此我们需要修改默认的代码。找到这个文件:

C:\InstantRails-2.0-win\rails_apps\gis\app\helpers\application_helper.rb。

修改application_helper.rb文件以和下面的清单13一致:

清单13:重载periodically_call_remote,以支持返回变量

[ruby]  view plain copy print ?
  1. # Methods added to this helper will be available to all templates in the application.  
  2. module ApplicationHelper  
  3.     def periodically_call_remote(options = {})  
  4.         variable = options[:variable] ||= 'poller'  
  5.         frequency = options[:frequency] ||= 10  
  6.         code = "#{variable} = new PeriodicalExecuter(function(){#{remote_function(options)}}, #{frequency})"  
  7.         javascript_tag(code)  
  8.     end  
  9. end  
最后,我们调用myUpdater.stop()停止定时器,调用myUpdater.resume()重启定时器。示例主页中,表格定时会变黄色,就是定时器启动的情况下,Ajax代码:     new Effect.Highlight('locations_div')
作用的效果。当我们按Draw Point按钮时,我们会发现浏览器上部出现了一个输入表:

图9:locations/new的RJS实现

这又是另外一个Ajax的例子。读者可以自己在主页的源代码(index.html.erb)中揣摩(http://localhost:3000/locations/new)。


7 ArcGIS JavaScriptAPI编程


7.1 ArcGIS Online地图服务

本文用的地图是ESRI的在线地图服务的地图数据。使用这个服务不需要客户端装任何东西。ArcGIS Online Map Server使用REST(Representational State Transfer)的对象访问协议。REST,表述性状态转移,只要使用网址,就可以很容易地创建、发布和使用“REST风格”的网络服务。相比REST之前的简单对象访问协议(SOAP),REST是轻量级的,使用简便、灵活。REST是各层次开发者利用ArcGISServer创建自定义应用的最简便方法。其实质是用URI(统一的资源标识,它是以某种统一的标准化的方式标识资源的一串字符串)描述互联网上的资源,所以没有开发工具的限制。

使用ArcGIS JSAPI可以快速的创建交互式的地图RIA应用——RIA(Rich Internet Applications)富互联网应用,具有高度互动性、丰富用户体验以及功能强大的客户端。基于REST API,我们可以为用户提供查询,显示要素等服务。利用叠加GP服务,可以为用户提供专业的分析结果。

7.2 如何显示一个ArcGIS Online地图

更多的资源请参考:http://help.arcgis.com/en/webapi/javascript/arcgis/help/jsapi_start.htm

本文的例子在:C:\InstantRails-2.0-win\rails_apps\gis\app\views\home\index.html.erb。

1)创建一个文本文件,复制下面的代码到文件中,然后文件保存为:arcgis-demo.html。

清单14:arcgis-demo.html

[html]  view plain copy print ?
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">  
  2. <html>   
  3. <head>  
  4.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
  5.     <title>ArcGIS Online Map Simplest Demo - cheungmine</title>  
  6.     <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.4/js/dojo/dijit/themes/claro/claro.css">  
  7.     <style type="text/css">  
  8.         html,body {  
  9.             height:100%;  
  10.             width:100%;  
  11.             margin:0;  
  12.         }  
  13.         body {  
  14.             background-color:#FFF;  
  15.             overflow:hidden;  
  16.             font-family:"Trebuchet MS";  
  17.         }  
  18.         #mainWindow {  
  19.             width:100%;  
  20.             height:100%;  
  21.             margin:0px;  
  22.             padding:0;  
  23.         }  
  24.         #mapDiv {  
  25.             background-color:#FFF;  
  26.             border:solid 1px #AEAEAE;  
  27.             margin:0px;  
  28.             padding:0;  
  29.         }  
  30.     </style>  
  31.     <%= javascript_include_tag :defaults %>  
  32.     <script type="text/javascript">  
  33.         var djConfig = {  
  34.             parseOnLoad: true  
  35.         };  
  36.     </script>  
  37.     <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.4">  
  38.     </script>  
  39.     <script type="text/javascript">  
  40.         dojo.require("dijit.dijit"); // optimize: load dijit layer  
  41.         dojo.require("dijit.layout.BorderContainer");  
  42.         dojo.require("dijit.layout.ContentPane");  
  43.         dojo.require("esri.map");  
  44.         dojo.require("esri.dijit.Scalebar");  
  45.         dojo.require("esri.toolbars.draw");  
  46.         dojo.require("esri.dijit.OverviewMap");  
  47.   
  48.         var map, spatialRef, initExtent;  
  49.       
  50.         // init on load  
  51.         function initGCS_WGS_1984() {  
  52.             // 4326 = GCS_WGS_1984  
  53.             spatialRef = new esri.SpatialReference({wkid:4326});  
  54.               
  55.             // china extent: Longitude(65~145), Latitude(9~55)  
  56.             initExtent = new esri.geometry.Extent(65, 9, 145, 55, spatialRef);  
  57.             map = new esri.Map("mapDiv");  
  58.             map.setExtent(initExtent);  
  59.               
  60.             dojo.connect(map, 'onLoad', function(map) {  
  61.                     var scalebar = new esri.dijit.Scalebar({map: map, scalebarUnit: "metric"});  
  62.   
  63.                     dojo.connect(dijit.byId('mapDiv'), 'resize', resizeMap);                          
  64.                     initToolbar(map);  
  65.                       
  66.                     // add the overview map   
  67.                     var overviewMapDijit = new esri.dijit.OverviewMap({map: map, visible:false});  
  68.                     overviewMapDijit.startup();  
  69.                 }  
  70.             );  
  71.                   
  72.             var basemapUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer";  
  73.             var basemap = new esri.layers.ArcGISTiledMapServiceLayer(basemapUrl);  
  74.             map.addLayer(basemap);  
  75.         }  
  76.           
  77.         // init on load  
  78.         function initWGS_1984_Web_Mercator_Auxiliary_Sphere() {  
  79.             // 102100 = WGS_1984_Web_Mercator_Auxiliary_Sphere  
  80.             spatialRef = new esri.SpatialReference({"wkid": 102100});  
  81.               
  82.             // china extent  
  83.             initExtent = new esri.geometry.Extent({  
  84.                             "xmin":-32971876.5210848,  
  85.                             "ymin":2044843.3806844242,  
  86.                             "xmax":-23921732.37212246,  
  87.                             "ymax":7127600.013534156,  
  88.                             "spatialReference":{"wkid":102100}  
  89.                         });  
  90.               
  91.             map = new esri.Map("mapDiv", {extent:initExtent, wrapAround180:true});  
  92.               
  93.             dojo.connect(map, 'onLoad', function(map) {  
  94.                     var scalebar = new esri.dijit.Scalebar({map: map, scalebarUnit: "metric"});  
  95.                     dojo.connect(dijit.byId('mapDiv'), 'resize', resizeMap);                          
  96.                     initToolbar(map);  
  97.                       
  98.                     // add the overview map   
  99.                     var overviewMapDijit = new esri.dijit.OverviewMap({map: map, visible:false});  
  100.                     overviewMapDijit.startup();  
  101.                 }  
  102.             );  
  103.               
  104.             var basemapUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer";  
  105.             var basemap = new esri.layers.ArcGISTiledMapServiceLayer(basemapUrl);  
  106.             map.addLayer(basemap);  
  107.               
  108.             var referenceUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer";  
  109.             var referenceLayer = new esri.layers.ArcGISTiledMapServiceLayer(referenceUrl);  
  110.             map.addLayer(referenceLayer);             
  111.         }  
  112.   
  113.         // resize map  
  114.         function resizeMap() {  
  115.             var resizeTimer;  
  116.             clearTimeout(resizeTimer);            
  117.             resizeTimer =   
  118.                 setTimeout(  
  119.                     function(){map.resize(); map.reposition();}, 500  
  120.                 );  
  121.         }  
  122.         
  123.         // show map on load   
  124.         // dojo.addOnLoad(initGCS_WGS_1984);       
  125.         dojo.addOnLoad(initWGS_1984_Web_Mercator_Auxiliary_Sphere);  
  126.     </script>  
  127. </head>  
  128. <body class="claro">  
  129.     <div id="mainWindow" dojotype="dijit.layout.BorderContainer" design="headline" gutters="false">  
  130.         <div id="mapDiv" dojotype="dijit.layout.ContentPane" region="center">  
  131.         </div>  
  132.         <!-- mapDiv -->  
  133.     <!-- mainWindow -->  
  134. </body>  
  135. </html>  
2)使用浏览器打开这个文件,就可以看到Web地图了。


图10:arcgis-demo.html展示的ArcGIS Online Map

7.3 ArcGIS JSAPI 使用了Dojo这个著名的Ajax开源JavaScript库

为什么是dojo?
1)Dojo宽松的使用许可
2)Dojo功能全面,事件设计模式、矢量图形支持、显示效果、widgets、Ajax、JSON等都是ArcServer客户端开发所需要的,并且Dojo利于扩展,方便Mashup应用
3)客户端有丰富的图表

参考:
http://dojotoolkit.org

http://dojocampus.org

8 安装和使用示例代码

本文的示例代码下载地址:http://download.csdn.net/source/3459994

8.1 安装并配置RoR环境

1) 下载InstantRails-2.0-win.zip:

        http://rubyforge.org/frs/download.php/29867/InstantRails-2.0-win.zip

2) 解压到 C:\ 下. 主目录名默认为:C:\InstantRails-2.0-win\InstantRails.exe

3) 此步可以忽略,下面的cpy-mysql-db.bat批处理中执行了这个过程:复制libmySQL.dll. 开始->运行 cmd:

        copy C:\InstantRails-2.0-win\mysql\bin\libmySQL.dll C:\InstantRails-2.0-win\ruby\bin\

4) 运行 C:\InstantRails-2.0-win\InstantRails.exe, 如果提示Apache端口被占用, 如下图:

图11:Apache端口错误消息

编辑修改下面的文件:

        C:\InstantRails-2.0-win\apache\conf\httpd.conf
将80改为81
        Listen 80=>81
        ...
        Port 80=>81

8.2 部署gis网站

1) 把gis.rar解压到 C:\InstantRails-2.0-win\rails_apps\ 目录下, 运行下面的批处理文件:


        C:\InstantRails-2.0-win\rails_apps\gis\cpy-mysql-db.bat
    这样我们的gis站点和MySQL数据库就部署好了.

2) 启动gis网站. 运行 C:\InstantRails-2.0-win\InstantRails.exe


图12:InstantRails主界面

选择[I.]->Rails Applications->Manage Rails Application..., 弹出下面的对话框,左边勾选 gis 检查框, 右边按 Start with Mongrel 启动gis网站服务。

图13:Rails程序管理器

3) 打开浏览器, 输入网址 http://localhost:3000/ 或http://127.0.0.1:3000/,即可看到网站主页.


图14:gis网站主页

8.3 使用gis网站

打开2个浏览器A和B, 都定位到网站主页: http://127.0.0.1:3000/

1) 浏览器A(IE7)模拟GPS点生成过程

按浏览器A的页面上部的 Draw Point 按钮, 然后在地图上的某个位置处点击, 再按页面上部的 Sumbit 按钮, 即把当前的记录提交到了后台数据库, 过几秒, 就可以看到这个黑点出现在地图上的点击处, 同时右边的表格中多了一条记录.

图15:模拟生成GPS点的过程

2)浏览器B(FireFox5)模拟监控者的画面

对于浏览器A中的操作, 5秒之后都会出现在浏览器B的主页上. 反之亦然.


图16:模拟监控者届面

9 关于Ruby、RoR的一些展望

本文写作时采用的是Ruby1.8.6和Rails2.0.2。显然这个版本已经过时了。但是因为InstantRails的存在,这个版本对于初学者特别合适。

Ruby是一门特别简单而功能强大的解释型语言。它一经推出,即风靡了整个业界。它是一个解释型语言。在脚本语言家族中,早期的Ruby版本,据说速度较慢。对于高性能、高度保密的需求上,可以用C语言的库来扩展它。2009年1月30日,ruby 1.9.1的正式版本如期发布! 1.9.1是ruby 1.9系列以来的第一个production ready的版本,这也标志着Ruby社区从此迈向了1.9的时代。ruby 1.9是ruby发展历史上的一个里程碑版本:

    1)ruby 1.9首次引入字节码即时编译技术,可以大大提高ruby本身的性能。根据之前的综合评测来看,1.9的性能大约是1.8.6的三倍左右,性能追上了Python。

    2)ruby 1.9正式支持内核多线程机制,可以大大提高ruby作为服务端程序的并发处理能力。

    3)ruby 1.9还引入了纤程这样的多任务并发处理机制,提供了轻量级并发处理能力。

因此,Ruby的一门很有潜力的新语言。Ruby on Rails(RoR)是近几年开始流行的新一代Web开发框架语言,其易用、敏捷的特性受到很多Web开发人员的瞩目。Rails是基于Ruby之上的开发动态Web的首选框架。在Web2.0时代,RoR是快速开发RIA应用的首选语言。RoR尤其适合于快速架构跨平台的各种类型的Web网站、开发云计算平台的RIA入口等等。

Ruby可以用于书写RoR的服务页面程序;也可以用Ruby脚本管理网络、服务器;Ruby也用于对象胶,组合各种系统服务、功能模块等等。

RoR结合Nginx(Nginx已经成为世界第三大Web服务器)在Linux平台上,可以以极小的代价开发和部署支持海量并发请求的、高性能的、可扩展的网站和云计算服务。利用C语言扩展Ruby后台模块,利用多核、异步、线程池等技术,可以满足高可靠性、可扩展性、服务逻辑隐藏等需求,同时使实现异步的、长时间、高负载的Web后台运算或云计算服务成为可能。

附录1: gis 主页源代码

清单15: ...\gis\app\views\home\index.html.erb
[html]  view plain copy print ?
  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">  
  2. <html>   
  3. <head>  
  4.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  
  5.     <meta http-equiv="X-UA-Compatible" content="IE=7,IE=9" />  
  6.     <!--The viewport meta tag is used to improve the presentation and behavior of the samples on iOS devices-->  
  7.     <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>  
  8.     <title>RoR with LBS Demo - cheungmine</title>  
  9.     <link rel="stylesheet" type="text/css" href="http://serverapi.arcgisonline.com/jsapi/arcgis/2.4/js/dojo/dijit/themes/claro/claro.css">  
  10.     <style type="text/css">  
  11.         html,body {  
  12.             height:100%;  
  13.             width:100%;  
  14.             margin:0;  
  15.         }  
  16.         body {  
  17.             background-color:#FFF;  
  18.             overflow:hidden;  
  19.             font-family:"Trebuchet MS";  
  20.         }  
  21.         #mainWindow {  
  22.             width:100%;  
  23.             height:100%;  
  24.             margin:0px;  
  25.             padding:0;  
  26.         }  
  27.         #header {  
  28.             border:solid 0px #FFF;  
  29.             border-bottom:1px solid #AEAEAE;  
  30.             background-color:#FFF;  
  31.             color:#CD853F;  
  32.             font-size:10pt;  
  33.             text-align:center;  
  34.             height:90px !important;  
  35.             height:80px;  
  36.             margin-bottom:3px;  
  37.             padding:0;            
  38.         }  
  39.         #new_location_div {  
  40.             border:solid 0px #FFF;  
  41.             background-color:#FFF;  
  42.             color:#CD853F;  
  43.             font-size:10pt;  
  44.             text-align:center;  
  45.             overflow:hidden;  
  46.             height:60px;  
  47.             margin-left:10px;  
  48.             padding:0;  
  49.         }  
  50.         #menusDiv {  
  51.             border:solid 0px #FFF;  
  52.             background-color:#FFF;  
  53.             color:#CD853F;  
  54.             font-size:10pt;  
  55.             text-align:right;  
  56.             height:30px;  
  57.             overflow:hidden;  
  58.             margin-right:20px;  
  59.             padding:0;            
  60.         }  
  61.         #rightPane {  
  62.             background-color:#FFF;  
  63.             border:solid 1px #AEAEAE;  
  64.             width:400px;  
  65.             overflow:hidden;  
  66.             margin:0px;  
  67.             padding:0;  
  68.         }  
  69.         #mapDiv {  
  70.             background-color:#FFF;  
  71.             border:solid 1px #AEAEAE;  
  72.             margin:0px;  
  73.             padding:0;  
  74.         }  
  75.         #measurementPaneDiv {  
  76.             background-color:#FFF;  
  77.             border:solid 0px #B8B8B8;  
  78.             height:130px;  
  79.             overflow:hidden;  
  80.             margin:0px;  
  81.             padding:0;  
  82.             display:yes;  
  83.         }  
  84.         #measurementDiv {  
  85.             background-color:#FFF;  
  86.             border:solid 0px #B8B8B8;  
  87.             font-size:10pt;  
  88.             height:100%;  
  89.             overflow:hidden;  
  90.             margin:0px;  
  91.             padding:0;  
  92.         }  
  93.         #locations_div {  
  94.             background-color:#FFF;  
  95.             height:100%;  
  96.             border: 0;  
  97.             margin: 0;  
  98.             padding:0;  
  99.         }         
  100.         #tb_users {  
  101.             border-collapse:collapse;  
  102.         }  
  103.         #tb_users th {  
  104.             font-size:8pt;  
  105.             white-space:nowrap;  
  106.         }  
  107.         #tb_users td {  
  108.             border:1px solid #EEF2FB;  
  109.             font-size:8pt;  
  110.             white-space:nowrap;  
  111.         }  
  112.           
  113.         #new_users {  
  114.             border-collapse:collapse;  
  115.             height:48px;  
  116.         }  
  117.         #new_users th {  
  118.             font-color:#000;  
  119.             font-size:8pt;  
  120.             white-space:nowrap;  
  121.             height:16px;  
  122.             margin: 0;  
  123.             padding:0;  
  124.         }  
  125.         #new_users td {  
  126.             border:0px solid #EEF2FB;  
  127.             font-size:8pt;  
  128.             white-space:nowrap;  
  129.             height:22px;  
  130.             margin: 0;  
  131.             padding:0;  
  132.         }  
  133.           
  134.         a { text-decoration: none; }  
  135.         h2, h3 { margin: 0 0 20px; text-shadow: 2px 2px #fff; }  
  136.         h2 { font-size: 28px; }  
  137.         h3 { font-size: 22px; }  
  138.         pre { background: #fff; width: 460px; padding: 10px 20px; border-left: 5px solid #ccc; margin: 0 0 20px; }  
  139.         input { margin: 0; padding: 0; }  
  140.       
  141.         .button {  
  142.             padding: 3px 5px;  
  143.             display: inline;  
  144.             background: #ABC url(button.png) repeat-x bottom;  
  145.             border: none;  
  146.             color: #fff;  
  147.             cursor: pointer;  
  148.             font-weight: bold;  
  149.             border-radius: 3px;  
  150.             -moz-border-radius: 3px;  
  151.             -webkit-border-radius: 3px;  
  152.             text-shadow: 1px 1px #666;  
  153.         }  
  154.         .button:hover {  
  155.             background-position: 0 center;  
  156.         }  
  157.         .button:active {  
  158.             background-position: 0 top;  
  159.             position: relative;  
  160.             top: 1px;  
  161.             padding: 3px 5px 2px;  
  162.         }  
  163.         .button.red { background-color: #e50000; }  
  164.         .button.purple { background-color: #9400bf; }  
  165.         .button.green { background-color: #58aa00; }  
  166.         .button.orange { background-color: #ff9c00; }  
  167.         .button.blue { background-color: #2c6da0; }  
  168.         .button.black { background-color: #333; }  
  169.         .button.white { background-color: #fff; color: #000; text-shadow: 1px 1px #fff; }  
  170.         .button.small { font-size: 75%; padding: 3px 7px; }  
  171.         .button.small:active { padding: 4px 7px 2px; background-position: 0 top; }  
  172.         .button.large { font-size: 125%; padding: 7px 12px; }  
  173.         .button.large:active { padding: 8px 12px 6px; background-position: 0 top; }  
  174.     </style>  
  175.     <%= javascript_include_tag :defaults %>  
  176.     <script type="text/javascript">  
  177.         var djConfig = {  
  178.             parseOnLoad: true  
  179.         };  
  180.     </script>  
  181.     <script type="text/javascript" src="http://serverapi.arcgisonline.com/jsapi/arcgis/?v=2.4">  
  182.     </script>  
  183.     <script type="text/javascript">  
  184.         dojo.require("dijit.dijit"); // optimize: load dijit layer  
  185.         dojo.require("dijit.layout.BorderContainer");  
  186.         dojo.require("dijit.layout.ContentPane");  
  187.         dojo.require("esri.map");  
  188.         dojo.require("esri.dijit.Measurement");          
  189.         dojo.require("esri.dijit.Scalebar");  
  190.         dojo.require("esri.toolbars.draw");  
  191.         dojo.require("esri.dijit.OverviewMap");  
  192.   
  193.         var map, toolbar, spatialRef, initExtent, defaultPointSymbol, defaultLineSymbol, defaultFillSymbol;  
  194.       
  195.         // init on load  
  196.         function initGCS_WGS_1984() {  
  197.             // 4326 = GCS_WGS_1984  
  198.             spatialRef = new esri.SpatialReference({wkid:4326});  
  199.               
  200.             // china extent  
  201.             initExtent = new esri.geometry.Extent(65, 9, 145, 55, spatialRef);  
  202.             map = new esri.Map("mapDiv");  
  203.             map.setExtent(initExtent);  
  204.               
  205.             dojo.connect(map, 'onLoad', function(map) {  
  206.                     var scalebar = new esri.dijit.Scalebar({map: map, scalebarUnit: "metric"});  
  207.   
  208.                     dojo.connect(dijit.byId('mapDiv'), 'resize', resizeMap);                          
  209.                     initToolbar(map);  
  210.                       
  211.                     // add the overview map   
  212.                     var overviewMapDijit = new esri.dijit.OverviewMap({map: map, visible:false});  
  213.                     overviewMapDijit.startup();  
  214.                 }  
  215.             );  
  216.                   
  217.             var basemapUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer";  
  218.             var basemap = new esri.layers.ArcGISTiledMapServiceLayer(basemapUrl);  
  219.             map.addLayer(basemap);  
  220.         }  
  221.           
  222.         // init on load  
  223.         function initWGS_1984_Web_Mercator_Auxiliary_Sphere() {  
  224.             // 102100 = WGS_1984_Web_Mercator_Auxiliary_Sphere  
  225.             spatialRef = new esri.SpatialReference({"wkid": 102100});  
  226.               
  227.             // china extent  
  228.             initExtent = new esri.geometry.Extent({  
  229.                             "xmin":-32971876.5210848,  
  230.                             "ymin":2044843.3806844242,  
  231.                             "xmax":-23921732.37212246,  
  232.                             "ymax":7127600.013534156,  
  233.                             "spatialReference":{"wkid":102100}  
  234.                         });  
  235.               
  236.             map = new esri.Map("mapDiv", {extent:initExtent, wrapAround180:true});  
  237.               
  238.             dojo.connect(map, 'onLoad', function(map) {  
  239.                     var scalebar = new esri.dijit.Scalebar({map: map, scalebarUnit: "metric"});  
  240.                     dojo.connect(dijit.byId('mapDiv'), 'resize', resizeMap);                          
  241.                     initToolbar(map);  
  242.                       
  243.                     // add the overview map   
  244.                     var overviewMapDijit = new esri.dijit.OverviewMap({map: map, visible:false});  
  245.                     overviewMapDijit.startup();  
  246.                 }  
  247.             );  
  248.               
  249.             var basemapUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer";  
  250.             var basemap = new esri.layers.ArcGISTiledMapServiceLayer(basemapUrl);  
  251.             map.addLayer(basemap);  
  252.               
  253.             var referenceUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/Reference/World_Boundaries_and_Places/MapServer";  
  254.             var referenceLayer = new esri.layers.ArcGISTiledMapServiceLayer(referenceUrl);  
  255.             map.addLayer(referenceLayer);             
  256.         }  
  257.   
  258.         // resize map  
  259.         function resizeMap() {  
  260.             var resizeTimer;  
  261.             clearTimeout(resizeTimer);            
  262.             resizeTimer =   
  263.                 setTimeout(  
  264.                     function(){map.resize(); map.reposition();}, 500  
  265.                 );  
  266.         }  
  267.           
  268.         function initToolbar(map) {  
  269.             // create symbol for drawing  
  270.             defaultPointSymbol = new esri.symbol.SimpleMarkerSymbol(  
  271.                 esri.symbol.SimpleMarkerSymbol.STYLE_CIRCLE, 11,  
  272.                 new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID,  
  273.                 new dojo.Color([255,255,255]), 2),  
  274.                 new dojo.Color([10,10,10, 1]));  
  275.                   
  276.             // create toolbar  
  277.             toolbar = new esri.toolbars.Draw(map);  
  278.             dojo.connect(toolbar, "onDrawEnd", addLocation);  
  279.               
  280.             //define a new line symbol and point symbol to use for measure tools  
  281.             var pms = new esri.symbol.PictureMarkerSymbol("images/flag.png", 24, 24);  
  282.             pms.setOffset(9,11);  
  283.             var sls = new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_DOT,  
  284.                         new dojo.Color([255,0,0,.55]), 4);  
  285.                           
  286.             var measurement = new esri.dijit.Measurement({  
  287.                     map: map,  
  288.                     lineSymbol:sls,  
  289.                     pointSymbol:pms  
  290.                 },   
  291.                 dojo.byId('measurementDiv')  
  292.             );  
  293.               
  294.             measurement.startup();  
  295.             // measurement.setTool("distance", true);  
  296.         }  
  297.         
  298.         // show map on load   
  299.         dojo.addOnLoad(initGCS_WGS_1984);      
  300.         // dojo.addOnLoad(initWGS_1984_Web_Mercator_Auxiliary_Sphere);  
  301.           
  302.         // add location to database when onDrawEnd fired  
  303.         function addLocation(geometry) {  
  304.             dojo.byId("inLong").value = geometry.x;  
  305.             dojo.byId("inLat").value = geometry.y;  
  306.               
  307.             var type = geometry.type;             
  308.             if (type === "point" || type === "multipoint") {  
  309.                 symbol = toolbar.markerSymbol;  
  310.             }  
  311.             else if (type === "line" || type === "polyline") {  
  312.                 symbol = toolbar.lineSymbol;  
  313.             }  
  314.             else {  
  315.                 symbol = toolbar.fillSymbol;  
  316.             }  
  317.               
  318.             map.graphics.add(new esri.Graphic(geometry, symbol));  
  319.         }  
  320.           
  321.         function isValidValue(val) {  
  322.             if (val==null || val=="")  
  323.                 return false;  
  324.             return true;  
  325.         }  
  326.           
  327.         // user location class  
  328.         function userLocation(user_id, recv_time, x_long, y_lat, z_elev, message) {  
  329.             this.valid = false;  
  330.             this.id = user_id;  
  331.             this.recv = recv_time;  
  332.             this.x = x_long;  
  333.             this.y = y_lat;  
  334.             this.z = z_elev;  
  335.             this.msg = message;  
  336.               
  337.             if (isValidValue(this.id) &&   
  338.                 isValidValue(this.recv) &&   
  339.                 isValidValue(this.x) &&   
  340.                 isValidValue(this.y))  
  341.             {  
  342.                 this.valid = true;            
  343.             }  
  344.         }  
  345.           
  346.         // add user location to map  
  347.         function addMapGraphics(user) {  
  348.             if (!user.valid)  
  349.                 return;               
  350.             var pt = new esri.geometry.Point(user.x, user.y, spatialRef);  
  351.             var graphic = new esri.Graphic(pt, defaultPointSymbol);  
  352.             map.graphics.add(graphic);  
  353.         }  
  354.           
  355.         // refresh locations  
  356.         function refreshLocations(tb) {  
  357.             // clear old first  
  358.             clearMapGraphics();  
  359.               
  360.             // we get table object and get its all tds  
  361.             var rows=tb.rows;  
  362.             for(i=1; i<rows.length; i++){  
  363.                 cols = rows[i].cells;  
  364.                 var user = new userLocation(cols[0].innerHTML,   
  365.                     cols[1].innerHTML, cols[2].innerHTML, cols[3].innerHTML, cols[4].innerHTML, cols[12].innerHTML);  
  366.                 addMapGraphics(user);                 
  367.             }  
  368.         }  
  369.           
  370.         function clearMapGraphics() {  
  371.             map.graphics.clear();  
  372.         }  
  373.           
  374.         var myMonitor = true;  
  375.         var myUpdater = null;  
  376.           
  377.         PeriodicalExecuter.prototype.resume = function(){  
  378.             if(!this.timer)  
  379.                 this.registerCallback();  
  380.         };  
  381.           
  382.         function startMonitor() {  
  383.             if (myUpdater != null)  
  384.             {  
  385.                 myUpdater.resume();  
  386.             }  
  387.         }  
  388.           
  389.         function stopMonitor() {  
  390.             if (myUpdater != null)  
  391.             {  
  392.                 myUpdater.stop();  
  393.             }  
  394.         }  
  395.     </script>  
  396. </head>  
  397. <body class="claro">  
  398.     <%= periodically_call_remote(  
  399.         :variable => "myUpdater",  
  400.         :condition => "myMonitor == true",  
  401.         :update => "locations_div",  
  402.         :url => {:controller=>"locations", :action =>"list_by"},  
  403.         :frequency => 5,  
  404.         :complete => "new Effect.Highlight('locations_div');refreshLocations(dojo.byId('tb_users'));") %>  
  405.           
  406.     <div id="mainWindow" dojotype="dijit.layout.BorderContainer" design="headline" gutters="false">  
  407.         <div id="header" dojotype="dijit.layout.ContentPane" region="top">  
  408.             <div id="new_location_div" dojotype="dijit.layout.ContentPane" region="center">  
  409.             </div>  
  410.             <div id="menusDiv" dojotype="dijit.layout.ContentPane" region="bottom">  
  411.                 <a href="#" class="button green" onclick="startMonitor();">Start Monitor</a>  
  412.                 <a href="#" class="button red" onclick="stopMonitor();">Stop Monitor</a>  
  413.                 <%= link_to_remote("Draw Point",  
  414.                     {  
  415.                       :update => "new_location_div",  
  416.                       :url => {:controller=>"locations", :action =>"new"},  
  417.                       :complete => "toolbar.activate(esri.toolbars.Draw.POINT);"  
  418.                     },  
  419.                     { :class => "button orange"} ) %>  
  420.                 <a href="#" class="button orange" onclick="clearMapGraphics();">Clear Graphics</a>  
  421.             </div>  
  422.         </div>  
  423.         <!-- header -->  
  424.   
  425.         <div id="mapDiv" dojotype="dijit.layout.ContentPane" region="center">  
  426.         </div>  
  427.         <!-- mapDiv -->  
  428.   
  429.         <div id="rightPane" dojotype="dijit.layout.BorderContainer" region="right" gutters="false" splitter="true">  
  430.             <div id="locations_div" dojotype="dijit.layout.ContentPane" region="center">  
  431.             </div>  
  432.             <!-- locations_div -->  
  433.               
  434.             <div id="measurementPaneDiv" dojotype="dijit.layout.ContentPane" region="bottom">  
  435.                 <div id="measurementDiv" style="height:100%;"></div>  
  436.             </div>  
  437.             <!-- measurementPaneDiv -->  
  438.         </div>  
  439.         <!-- rightPane -->  
  440.     </div>  
  441.     <!-- mainWindow -->  
  442. </body>  
  443. </html>  

附录2: 参考文献

1) AgileWebDevelopmentWithRails-3rdEd.pdf
2) building_dynamic_web_2.0_websites_with_ruby_on_rails.pdf
3) OReilly.Ajax.on.Rails.Dec.2006.chm
4) Enterprise Integration with Ruby - A Pragmatic Guide.pdf
5) OReilly.Dojo.The.Definitive.Guide.Jun.2008.pdf
6) ArcGIS JavaScript API开发—初级篇_白明.pdf
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值