对比三种GoogleMap图标操作处理,谈如何构造快速响应的GoogleMap图标叠加操作
很多情况下,我们可以基于GoogleMap做GIS方面的应用,只要涉及到地图的相关操作,基本上都可以派生出很多应用,如可以用在配电线路、水管布线、地标附加等操作。本文主要介绍基于图标叠加的应用,通过三种不同的GoogleMap操作,来分析各种操作的优劣,寻找出最符合实际、最高效简洁的操作方式,指导我们今后对GoogleMap的应用操作。
方式一:使用Javascript和Html混合方式处理。
在页面前台给Javascript赋相关的变量,在后台把相关属性内容(包含InfoWindows显示的内容,图标坐标等)赋值给脚本对象, 由脚本分拆对象数据,然后添加图标。如下面代码所示:

代码
<
script
type
="text/javascript"
charset
="utf-8"
>
var
map
=
null
;
var
xmapx
=
"
<%=map_x%>
"
;
var
ymapy
=
"
<%=map_y%>
"
;
var
title
=
"
<%=title%>
"
;
var
device_id
=
"
<%=deviceid%>
"
;
var
map_no
=
"
<%=mapno%>
"
;
var
center
=
"
<%=centers%>
"
;
var
districtname
=
"
<%=districtname%>
"
;
var
newIcon;
function
initialize() {
var
mapdivw
=
screen.width
-
250
;
var
mapdivh
=
screen.height
-
340
;
var
mapdiv
=
document.getElementById(
"
map_canvas
"
);
mapdiv.style.width
=
mapdivw;
mapdiv.style.height
=
mapdivh;
if
(GBrowserIsCompatible()) {
map
=
new
GMap2(document.getElementById(
"
map_canvas
"
));
//
新建一个地图
map.setCenter(
new
GLatLng(
23.136216352329377
,
113.32762241363525
),
15
);
//
定义地图中心坐标
map.addControl(
new
GLargeMapControl());
showmarker();
}
else
{
alert(
'
你使用的浏览器不支持 Google Map!
'
);
}
}
function
showmarker() {
var
mapxx
=
xmapx.split(
"
|
"
);
var
mapyy
=
ymapy.split(
"
|
"
);
var
title_
=
title.split(
"
|
"
);
var
devices_id
=
device_id.split(
"
|
"
);
var
mapnos
=
map_no.split(
"
|
"
);
var
firstPoint
=
null
;
//
获得位置,移动到此处
for
(
var
i
=
0
; i
<
mapxx.length
-
1
; i
++
) {
var
_title
=
title_[i].replace(
/
<br>
/
g,
'
\n
'
);
newIcon
=
new
GIcon(G_DEFAULT_ICON);
//
newIcon.iconSize=new GSize(48, 48);
newIcon.image
=
"
http://gmaps-samples.googlecode.com/svn/trunk/markers/blue/marker
"
+
(i
+
1
)
+
"
.png
"
//
newIcon = MapIconMaker.createMarkerIcon({ width: 48, height: 48, primaryColor: "#00ff00" });
point
=
new
GLatLng(mapxx[i], mapyy[i]);
//
经纬度
if
(firstPoint
==
null
) {
firstPoint
=
point;
}
markers(point, _title, title_[i], devices_id[i]);
}
map.panTo(firstPoint);
//
移动到第一个点
}
function
markers(point, _title, title_br, _device_id) {
var
marker
=
new
GMarker(point, { draggable:
false
, icon: newIcon, title: _title });
//
markerOptions); //新建一个标记
map.addOverlay(marker)
//
叠加一个层
GEvent.addListener(marker,
"
click
"
,
function
() {
marker.openInfoWindowHtml(
"
<table border=0><tr><td>
"
+
title_br
+
"
</td></tr></table>
"
);
});
}
最终HTML生成会有很多字符的变量,如下面所示:

代码
<
script
type
="text/javascript"
charset
="utf-8"
>
var
map
=
null
;
var
xmapx
=
"
23.1403303909433650|23.1391267764026970|23.1348449780739640|23.13282242210374|23.1326448303667040|23.1391761050798230|23.13819939389483|23.1358414456525060|23.1322699137051440|23.1325363019671920|23.1306123748529370|
"
;
var
ymapy
=
"
113.32088470458984|113.32077741622925|113.32098126411438|113.32255840301513|113.32709670066833|113.32873821258545|113.32922101020813|113.32914590835571|113.32933902740478|113.33328723907470|113.32048773765564|
"
;
var
title
=
"
停车场名称:中石化大厦停车场<br>停车场地址:中石化大厦停车场<br>停车场类型:商业<br>总车位数:600<br>当前空车位:521<br>收费类型:政府指导价<br>收费标准:<br>|停车场名称:城建大厦停车场<br>停车场地址:<br>停车场类型:<br>总车位数:240<br>当前空车位:196<br>收费类型:<br>收费标准:<br>|停车场名称:维多利亚广场停车场<br>停车场地址:<br>停车场类型:<br>总车位数:338<br>当前空车位:304<br>收费类型:<br>收费标准:<br>|停车场名称:天河城停车场<br>停车场地址:广州市天河区天河路208号天河城广场地下车库经营室<br>停车场类型:<br>总车位数:800<br>当前空车位:573<br>收费类型:<br>收费标准:<br>|停车场名称:正佳广场停车场<br>停车场地址:<br>停车场类型:商业<br>总车位数:1500<br>当前空车位:925<br>收费类型:<br>收费标准:<br>|停车场名称:南方证券大厦停车场<br>停车场地址:<br>停车场类型:商业<br>总车位数:134<br>当前空车位:106<br>收费类型:<br>收费标准:<br>|停车场名称:金利来大厦停车场<br>停车场地址:<br>停车场类型:商业<br>总车位数:120<br>当前空车位:47<br>收费类型:<br>收费标准:<br>|停车场名称:财富大厦停车场<br>停车场地址:<br>停车场类型:商业<br>总车位数:157<br>当前空车位:0<br>收费类型:<br>收费标准:<br>|停车场名称:创展中心停车场<br>停车场地址:<br>停车场类型:商业<br>总车位数:340<br>当前空车位:325<br>收费类型:<br>收费标准:<br>|停车场名称:丰兴大厦停车场<br>停车场地址:<br>停车场类型:商业<br>总车位数:530<br>当前空车位:433<br>收费类型:<br>收费标准:<br>|停车场名称:东洲大厦停车场<br>停车场地址:<br>停车场类型:商业<br>总车位数:100<br>当前空车位:74<br>收费类型:<br>收费标准:<br>|
"
;
var
device_id
=
"
P-0001|P-0002|P-0003|P-0007|P-0008|P-0006|P-0005|P-0004|P-0009|P-0010|P-0011|
"
;
.....................
这样方式处理,虽然较容易理解,不过由于是代码混合,操作及扩展还是相对比较麻烦,而且代码量也很多,多数是Javascript脚本,操作控制也不是很方便。 Asp.net后台代码还需要给这些变量赋值,每个项目之间通过|分号来分隔,这样对于少量的图标操作,也倒是响应很快。但是对于超过几十个乃至上百个,图标操作处理就变得非常缓慢,因此这种方式处理,是极为不好的。
方式二:使用GGeoXml的Javascript对象。
通过动态的URL对象,根据不同的参数,返回不同的XML对象流给Javascript脚本处理,这种方式简洁明了,而且速度也非常快,属于不错的处理方式。主要的代码如下所示:
代码
<
script
type
="text/javascript"
>
var
map;
var
geoXml;
var
center
=
"
<%=centers%>
"
;
function
initialize() {
if
(GBrowserIsCompatible()) {
//
地址必须是公网能访问的地址,否则不会显示图标
map
=
new
GMap2(document.getElementById(
"
map_canvas
"
));
center_set();
map.addControl(
new
GLargeMapControl());
geoXml
=
new
GGeoXml(
"
http://219.136.**.**/Pages/Expert/
GetParkKML.aspx?area=<%=Server.UrlEncode(Request.QueryString["area"])%>");
map.addOverlay(geoXml);
}
else
{
alert(
'
你使用的浏览器不支持 Google Map!
'
);
}
}
..................
这样把主动权交给GetParkXML.aspx来组装数据了,这个页面主要负责构造相应的KML文件(就是一个XML文件)给Javascript对象,这个页面的代码大致如下所示:

代码
{
protected void Page_Load(object sender, EventArgs e)
{
string area = Request.QueryString["area"];
string areaCountry = area;//行政区
DataTable table = BLLFactory
<
Enterprise
>
.Instance.FindByStreetParkAreaName("", areaCountry);
StringBuilder str = new StringBuilder();
str.Append("
<?
xml version=\"1.0\" encoding=\"UTF-8\"
?>
\r\n");
str.Append("
<
kml
xmlns
=\"http://www.opengis.net/kml/2.2\"
>
\r\n");
str.Append("
<
Document
>
\r\n\r\n");
//必须用公网地址:http://gmaps-samples.googlecode.com/svn/trunk/markers/blue/blank.png
str.Append("\t
<
Style
id
=\"myStationStyles\"
>
<IconStyle><scale>1</scale><Icon><href>http://219.136.*.*/Themes/Default/parking.png</href></Icon></IconStyle>
</
Style
>
");
StringBuilder sbTitle = new StringBuilder();
foreach (DataRow row in table.Rows)
{
str.Append("
<
Placemark
>
\r\n");
str.Append(string.Format("\t
<
name
>
<!
[CDATA[{0}]]
>
</
name
>
\r\n", GetParkName(row)));
str.Append(string.Format("\t
<
description
>
<!
[CDATA[{0}]]
>
</
description
>
\r\n", GetParkDescription(row)));
str.Append("\t
<
styleUrl
>
#myStationStyles
</
styleUrl
>
\r\n");
string longLat = string.Format("{0},{1},0", row["LONGITUDE"], row["LATITUDE"]);
str.Append(string.Format("\t
<
Point
><
coordinates
>
{0}
</
coordinates
></
Point
>
\r\n", longLat));
str.Append("
</
Placemark
>
\r\n");
}
str.Append("
</
Document
>
\r\n");
str.Append("
</
kml
>
");
Response.Clear();
Response.ContentType = "application/vnd.google-earth.kml+xml";
Response.Write(str.ToString());
Response.Flush();
Response.End();
}
.............
这种方式是比较通用的处理方式,很多Googmap使用者应该都是基于此类型操作较多,详细还可以参考一篇文章介绍《
基于google map api开发web和google earth的KML地标插件
》,作者写的思路比较清晰,值得参考。
该方式处理的问题,就是图标数量比较多的时候(如500个以上),速度比较慢,甚至有时候就不显示图标了,不知何故,不过对于小于这个数量级的,一般还是不错的。
3、 方式三:基于方式二做进一步的改进。
由于方式二,还是每次都会请求生成图标的KML文件,生成的过程如果涉及操作逻辑比较复杂,数量比较多的时候,就会出现比较缓慢,或者甚至显示不了图标的情况。那么我们如果认为图标内容在一段的时间内不会发生太大的变化的话,其实可以预先生成好XML文件,然后直接给Javascript前台操作显示,这样处理肯定快很多,而且也可以避免方式二有时候出不来图标的情况。
处理操作,其实很简单,就是把方式二的代码
geoXml = new GGeoXml("http://219.136.**.**/Pages/Expert/
GetParkKML.aspx?area=<%=Server.UrlEncode(Request.QueryString["area"])%>");
修改为下面代码即可。
geoXml = new GGeoXml("http://219.136.*.*/Pages/Expert/
<%
=
fileName
%>
.kml");
然后在页面后台中,我们根据不同的条件,指定不同的XML文件给它就可以了。
public
string
centers
=
"
23.140330390943365,113.32088470458984|
"
;
public
string
fileName
=
""
;
public
string
googleMapKey
=
""
;
protected
void
Page_Load(
object
sender, EventArgs e)
{
googleMapKey
=
Helper.GetGoogleMapKey(Request.Url.AbsoluteUri);
string
area
=
Request.QueryString[
"
area
"
];
string
areaCountry
=
area;
//
行政区
if
(
string
.IsNullOrEmpty(area))
{
centers
=
"
23.136216352329377, 113.32762241363525
"
;
return
;
}
string
centerLatlng
=
BLLFactory
<
Enterprise
>
.Instance.FindAreaCenterLatLng(area);
if
(
!
string
.IsNullOrEmpty(centerLatlng))
{
centers
=
centerLatlng;
}
fileName
=
area.GetHashCode().ToString();
//
不能用中文,故出此策
string
filePath
=
Server.MapPath(
"
.
"
)
+
"
/
"
+
fileName
+
"
.kml
"
;
if
(
!
File.Exists(filePath))
{
CreateMapData();
}
else
{
//
可指定更新的日期自动对比
DateTime dtLastTime
=
GetLastWriteTime(filePath);
if
(DateTime.Now
>
dtLastTime.AddMonths(
1
))
{
CreateMapData();
}
}
}
private
void
CreateMapData()
{
string
area
=
Request.QueryString[
"
area
"
];
if
(
!
string
.IsNullOrEmpty(area))
{
string
httpUrl
=
Request.Url.AbsoluteUri;
int
eindx
=
httpUrl.LastIndexOf(
'
/
'
);
string
dataurl
=
httpUrl.Substring(
0
, eindx)
+
string
.Format(
"
/GetParkKML.aspx?area={0}
"
, Server.UrlEncode(area));
WebClient client
=
new
WebClient();
client.Encoding
=
Encoding.UTF8;
string
content
=
client.DownloadString(dataurl);
fileName
=
area.GetHashCode().ToString();
//
不能用中文,故出此策
string
filePath
=
Server.MapPath(
"
.
"
)
+
"
/
"
+
fileName
+
"
.kml
"
;
File.WriteAllText(filePath, content, Encoding.UTF8);
}
}
///
<summary>
///
取文件最后存储时间
///
</summary>
///
<param name="fullpath"></param>
///
<returns></returns>
public
static
DateTime GetLastWriteTime(
string
fullpath)
{
FileInfo fi
=
new
FileInfo(fullpath);
return
fi.LastWriteTime;
}
}
最后,还应该提供一个按钮给用户,实现数据的实时更新,而不是每次由系统根据文件的情况更新,这样可以给用户更好的选择,保证数据的及时性。
protected
void
btnRefreshData_Click(
object
sender, ImageClickEventArgs e)
{
string
area
=
Request.QueryString[
"
area
"
];
CreateMapData();
string
url
=
string
.Format(
"
ParkGisSearch.aspx?area={0}
"
, Server.UrlEncode(area));
Response.Redirect(url);
}
实际效果,这样在操作近千个图标的时候,速度非常快,比前面两种都快得多,而且也不会出现有时候方式二呈现不了图标的情况,基本上解决效果还是比较满意的。。实际项目的效果截图如下所示。