众所周知,像天地图和e都市的地图都是以切片的形式存放在服务端的,系统根据用户选择的范围加载该范围的瓦片地图,这比传统的实时渲染地图的响应速度更快。google地图和baidu地图的原理也不外乎如此。
所以说,如果本地硬盘上有瓦片地图,或者我们知道瓦片地图在远程服务器端的组织形式,利用简单的javascript脚本语言和浏览器就可以实现对地图的浏览,通俗地说,这其实就是一个图片浏览器。考虑到远程服务器需要网络连接,最近利用闲暇时间将长沙市范围的e都市上的瓦片下载到本地,这样在没有网络的情况下也能浏览地图了。
采用网上广泛流传的完全利用js脚本写的开源“webgis完整功能例子”,换上本地硬盘上下载好的长沙范围内e都市地图,效果图如下。
当然,以上是网络上js高手写的API,功能不是很强大,但是至少为我等开发者提供了值得借鉴的思路。
esri也提供了可以浏览瓦片地图的API,包括javascript API,silverlight API和flex API,作为客户端语言,这三者提供的功能大致相似,甚至在类的命名上都保持了高度的一致性。利用arcgis api for javascript同样可以将下载到本地的瓦片和远程服务器端的瓦片进行地图浏览,本人结合最近做的利用ArcGIS API for Flex(以下简称ags4fx)加载天地图的瓦片地图来说明该过程,javascript api和silverlight api可以参考该方法加载瓦片地图。
根据最新的ags4fx 2.4可知,esri为我们提供了TiledMapServiceLayer类,这个类正是所有瓦片地图服务都必须继承的类,像ArcGISTiledMapServiceLayer, OpenStreetMapLayer, VETiledLayer等esri提供的瓦片类都是继承了该类的,所以我们要扩展该TiledMapServiceLayer类,名字暂且叫TianDiTuTiledMapServiceLayer。
从TiledMapServiceLayer类的API可知,fullExtent属性、tileInfo属性、units属性和getTileURL()方法是子类必须要重写的,于是最简单的TianDiTuTiledMapServiceLayer类定义如下:
package
tdt
{
import
com.esri.ags.SpatialReference;
import
com.esri.ags.geometry.Extent;
import
com.esri.ags.geometry.MapPoint;
import
com.esri.ags.layers.TiledMapServiceLayer;
import
com.esri.ags.layers.supportClasses.LOD;
import
com.esri.ags.layers.supportClasses.TileInfo;
import
flash.net.URLRequest;
public
class
TianDiTuTiledMapServiceLayer
extends
TiledMapServiceLayer
{
private
var _tileInfo:TileInfo;
/*
一幅完整的图片url有如下格式:
http://tile0.tianditu.com/DataServer?T=sbsm0210
&X=1&Y=1&L=1
*/
private
var _baseURL:String;
/*
http://tile
*/
private
var _baseURLs:Array;
/*
由诸如.tianditu.com/DataServer?T=sbsm0210组成的数组
*/
private
var _initExtent:String;
private
var _id:String;
private
var _name:String;
private
var _alpha:Number;
private
var _visible:Boolean;
public
function TiandituTiledMapServiceLayer()
{
this
._tileInfo
=
new
TileInfo();
this
._baseURLs
=
[];
this
._initExtent
=
null
;
this
.buildTileInfo();
//
设置tileinfo信息
setLoaded(
true
);
}
public
function set baseURL(baseurl:String):
void
{
_baseURL
=
baseurl;
}
public
function set baseURLs(baseurls:Array):
void
{
_baseURLs
=
baseurls;
}
override
public
function get fullExtent() : Extent
{
return
new
Extent(
-
180
,
-
90
,
180
,
90
,
new
SpatialReference(
4326
));
}
public
function set initExtent(initextent:String):
void
{
this
._initExtent
=
initextent;
}
override
public
function get initialExtent() :Extent
{
if
(
this
._initExtent
==
null
)
//
如果没有配置initExtent节点,则默认初始范围为长沙市区
return
new
Extent(
111.9
,
27.85
,
114.25
,
28.67
,
new
SpatialReference(
4326
));
var coors:Array
=
this
._initExtent.split(
"
,
"
);
return
new
Extent(Number(coors[
0
]), Number(coors[
1
]), Number(coors[
2
]) ,Number(coors[
3
]),
new
SpatialReference(
4326
));
}
override
public
function get spatialReference() : SpatialReference
{
return
new
SpatialReference(
4326
);
}
override
public
function get tileInfo() : TileInfo
{
return
this
._tileInfo;
}
override
public
function get units() : String
{
return
"
esriDecimalDegrees
"
;
}
override
protected
function getTileURL(level:Number, row:Number, col:Number) : URLRequest
{
var url:String
=
null
;
var rank:Number
=
this
._baseURLs.length
/
2
;
var tempLevel:Number
=
0
;
for
(var i:Number
=
0
; i
<
rank; i
++
)
{
if
(tempLevel
<=
level
&&
level
<
Number(
this
._baseURLs[i
*
2
]))
{
url
=
this
._baseURLs[i
*
2
+
1
];
break
;
}
if
(i
!=
rank
-
1
)
tempLevel
=
Number(
this
._baseURLs[i
*
2
]);
}
var urlRequest:String
=
this
._baseURL
+
String((Math.round(Math.random()
*
6
)
+
1
))
+
url
+
"
&X=
"
+
String(col)
+
"
&Y=
"
+
String(row)
+
"
&L=
"
+
String((level
+
1
));
return
new
URLRequest(urlRequest);
}
private
function buildTileInfo() :
void
{
this
._tileInfo.height
=
256
;
this
._tileInfo.width
=
256
;
this
._tileInfo.origin
=
new
MapPoint(
-
180
,
90
);
this
._tileInfo.spatialReference
=
new
SpatialReference(
4326
);
this
._tileInfo.lods
=
new
Array();
this
._tileInfo.lods
=
[
new
LOD(
0
,
0.703125
,
2.95498e+008
),
new
LOD(
1
,
0.351563
,
1.47749e+008
),
new
LOD(
2
,
0.175781
,
7.38744e+007
),
new
LOD(
3
,
0.0878906
,
3.69372e+007
),
new
LOD(
4
,
0.0439453
,
1.84686e+007
),
new
LOD(
5
,
0.0219727
,
9.2343e+006
),
new
LOD(
6
,
0.0109863
,
4.61715e+006
),
new
LOD(
7
,
0.00549316
,
2.30857e+006
),
new
LOD(
8
,
0.00274658
,
1.15429e+006
),
new
LOD(
9
,
0.00137329
,
577144
),
new
LOD(
10
,
0.000686646
,
288572
),
new
LOD(
11
,
0.000343323
,
144286
),
new
LOD(
12
,
0.000171661
,
72143
),
new
LOD(
13
,
8.58307e-005
,
36071.5
),
new
LOD(
14
,
4.29153e-005
,
18035.7
),
new
LOD(
15
,
2.14577e-005
,
9017.87
),
new
LOD(
16
,
1.07289e-005
,
4508.9
),
new
LOD(
17
,
5.36445e-006
,
2254.47
)
];
}
}
}
在mxml页面,配置地图参数如下:
<?
xml version="1.0" encoding="utf-8"
?>
<
s:Application
xmlns:fx
="http://ns.adobe.com/mxml/2009"
xmlns:s
="library://ns.adobe.com/flex/spark"
xmlns:viewer
="com.esri.viewer.*"
xmlns:tdt
="tdt.*"
>
<
esri:Map
>
<
tdt:TianDiTuTiledMapServiceLayer
>
<
tdt:baseURL
>
http://tile
</
tdt:baseURL
>
<
tdt:baseURLs
>
<
mx:String
>
10
</
mx:String
>
<
mx:String
>
.tianditu.com/DataServer?T=A0512_EMap
</
mx:String
>
<
mx:String
>
12
</
mx:String
>
<
mx:String
>
.tianditu.com/DataServer?T=B0627_EMap1112
</
mx:String
>
<
mx:String
>
18
</
mx:String
>
<
mx:String
>
.tianditu.com/DataServer?T=siwei0608
</
mx:String
>
</
tdt:baseURLs
>
</
tdt:TianDiTuTiledMapServiceLayer
>
<
tdt:TianDiTuTiledMapServiceLayer
>
<
tdt:baseURL
>
http://tile
</
tdt:baseURL
>
<
tdt:baseURLs
>
<
mx:String
>
10
</
mx:String
>
<
mx:String
>
.tianditu.com/DataServer?T=sbsm0210
</
mx:String
>
<
mx:String
>
11
</
mx:String
>
<
mx:String
>
.tianditu.com/DataServer?T=e11
</
mx:String
>
<
mx:String
>
12
</
mx:String
>
<
mx:String
>
.tianditu.com/DataServer?T=e12
</
mx:String
>
<
mx:String
>
13
</
mx:String
>
<
mx:String
>
.tianditu.com/DataServer?T=e13
</
mx:String
>
<
mx:String
>
14
</
mx:String
>
<
mx:String
>
.tianditu.com/DataServer?T=eastdawnall
</
mx:String
>
<
mx:String
>
18
</
mx:String
>
<
mx:String
>
.tianditu.com/DataServer?T=sbsm1518
</
mx:String
>
</
tdt:baseURLs
>
<
tdt:initExtent
>
111.9, 27.85, 114.25, 28.67
</
tdt:initExtent
>
</
tdt:TianDiTuTiledMapServiceLayer
>
<
tdt:TianDiTuTiledMapServiceLayer
>
<
tdt:baseURL
>
http://tile
</
tdt:baseURL
>
<
tdt:baseURLs
>
<
mx:String
>
10
</
mx:String
>
<
mx:String
>
.tianditu.com/DataServer?T=A0610_ImgAnno
</
mx:String
>
<
mx:String
>
14
</
mx:String
>
<
mx:String
>
.tianditu.com/DataServer?T=B0530_eImgAnno
</
mx:String
>
<
mx:String
>
18
</
mx:String
>
<
mx:String
>
.tianditu.com/DataServer?T=siweiAnno68
</
mx:String
>
</
tdt:baseURLs
>
</
tdt:TianDiTuTiledMapServiceLayer
>
</
esri:Map
>
</
s:Application
>
加载地图后的 flex页面如下:
根据这个思路,同样可以利用ags4fx API加载e都市的瓦片地图。。
重复上面的话,利用esri提供的javascript api和silverlight api实现这个效果过程是类似的,在此不赘述。