Lat铺设平面零件 2: 高级 谷歌地图. NET 控件用法

分享于 

19分钟阅读

Web开发

  繁體

介绍

这是三篇文章系列文章的第二篇文章,研究了开发定制 ASP.NET 服务器控件,以使使用 谷歌地图 API更容易。 NET开发者。 本文假设你已经阅读了 ,并熟悉 谷歌地图 API。 你可能会在文章中看到关于"控件。GoogleMaps控件。GMap控件等"的引用。 我没有创建 谷歌地图 API,我只是使用 C#。XML和XSL创建了 ASP.NET的包装器。

本文的主要目标是向你展示. NET 包装器对于 谷歌地图 API有多强大。 本文所介绍的所有内容都可以通过它的他技术( 如 JavaScript。PHP。Java。等等 ) 来完成。 这也使用面向对象的方法来实现 谷歌地图 交互。

本文介绍的高级功能包括:

  • 覆盖数据绑定- 将数据库纬度/lng值直接绑定到 GMap
  • 客户端回调- 以客户端 GMap 事件的结果运行服务器端代码。
  • GMap postback 状态- 在 postback/回拨后获取有关你的GMap的一些数据。

设置和配置

地图很无聊,没有附带的GIS数据。 我将展示的三个高级示例将使用大约 5,000个数据点。 代码下载中包含的是创建用于示例中的MS SQL Server 数据库和表的SQL脚本。 数据库中的数据库都可以使用,访问,MySQL,firebird 等等,下载中包含的数据库不是好数据库设计的例子,只是用于文章目的。 这些例子中使用的数据是来自许多因特网站点的免费( 以原始形式)。 如果你想要我的修改数据的副本,请在文章( 并给我一些反馈形式的反馈) 底部的消息板上放一行。

好东西

downloadable代码( 请参阅上面的下载源文件) 包含一个叫做TestWeb的web项目,它有三个( 3 ) 高级示例,关于如何在应用程序中使用我的GMap 控件。 如果你已经从部分下载代码,那么可以将第1部分的代码解压缩到它的上面。 在创建高级示例时,对 GMap 控件和关联的XSL和JavaScript文件进行了一些更改。 这些更改都不会破坏部件 1中的任何基本示例。 如果你已经自己尝试了该控件,你可以看到 changes.txt 文件中的文档化更改。 你可以在这里找到所有三个示例

ColoradoCounties.aspx

__Show Me__

本示例使用 GMap 控件的客户端回调和覆盖数据绑定高级功能。 如果你不熟悉客户端回调,请查看我关于异步JavaScript和 XML ( AJAX ) 框架框架的文章。 有关数据绑定的刷新,请参见掌握 ASP.NET 数据绑定应用程序。

代码段 below 创建一个 GMap 控件,并将 EnableClientCallBacks 调用设置为 True 代码还将事件处理程序 gMap_MarkerClick() 分配给 GMapMarkerClick 事件。

<wcp:GMaprunat="server"id="gMap"Width="750px"Height="525px"EnableClientCallBacks="True"OnMarkerClick="gMap_MarkerClick"/>

现在,在单击地图 marker 时,gMap_MarkerClick() 中发现的服务器端代码将被执行。 Sweet table below 显示了可以作为客户端回调实现的服务器端事件的完整 List: !

事件名称事件参数
GMap.Click发件人- 单击的GMap
GPointEventArgs - 单击 GMapGPoint
GMap.MarkerClick发送者- 一个 GMarker 实例,代表 marker。
GPointEventArgs - 单击 marker的GPoint
GMap.MoveStartSender - 已经移动的GMap
GPointEventArgs - 在移动开始时表示 GMap的中心纬度/lng坐标的GPoint
GMap.MoveEndSender - 已经移动的GMap
GPointEventArgs - 在移动结束时表示 GMap的中心纬度/lng坐标的GPoint
GMap.ZoomSender - 已经缩放的GMap
GMapZoomEventArgs - 旧的和新的缩放值。

页面中还包括一些客户端事件。 只要单击 marker,代码 below 就会在地图上打开一个信息窗口。 信息窗口将包含 marker的ID和单词"县"。 在 ColoradoCounties.aspx. cs中,我们将检查将标识分配给标记的代码 behind。

function GMarker_Click()
{
 this.openInfoWindowHtml(this.id + " County");
}

每当关闭信息窗口时,代码 below 将执行。 代码搜索映射,以查找与 marker 相同的一个 NAME。 如果找到多段线,则将它的从地图中删除。 这就是从地图上清除县边界的代码:

function GMarker_InfoWindowClose()
{
 var pLineId = this.id + "Boundary";
 var pLine = this.map.getOverlayById(pLineId);
 if( pLine )
 this.map.removeOverlay(pLine);
}

ColoradoCounties.aspx.cs

这就是魔法发生之所在。 当页面加载时,代码首先通过适当的缩放级别将地图置于科罗拉多的上方。 然后代码查询数据库,获取科罗拉多( 有关数据库的更多信息,请参见设置和配置 上面 ) 每个县的NAME。纬度和经度。 返回的数据以 DataSet的形式返回,然后将它的分配给 GMapDataSource。 在 finally 中,我们告诉 GMap 哪个数据库列对应于每个县的MarkerId。经度和纬度。 呈现 GMap 时,它将使用数据库值的位置和ID添加一个 marker。

gMap.CenterAndZoom(new GPoint(-105.5F, 39F), 10);
DataSet ds = GetCounties();
gMap.DataSource = ds;
gMap.DataMarkerIdField = "CountyName";
gMap.DataLongitudeField = "Longitude";
gMap.DataLatitudeField = "Latitude";
gMap.DataBind();
gMap.AddControl(new GSmallMapControl());

在ASPX页中将 gMap_MarkerClick() 分配给 MarkerClick 事件时记得? 现在我们将检查与事件处理程序关联的代码。 这里的目标是从代表每个县边界的数据库中读取纬度/lng值。 我们将获取这些值并将它们转换为一个 GPolyline,它将在 GMap 上显示红色的边界。 出于性能原因,我们使用缓存来加快客户端调用的速度。

protectedstring gMap_MarkerClick(object s, GPointEventArgs pea)
{
 GMarker gm = s as GMarker;
 if( gm!= null )
 {
 string gpTransform = Cache[gm.Id] asstring;
 if( gpTransform == null )
 {

如果边界还没有缓存,我们将查询纬度/lng值数据库。 因为在页面加载中我们使用数据绑定将县号分配给 ID,我们使用相同的值( gm.Id ) 来查询数据库的边界值。

GPolyline gp = GetBoundaryByCounty( gm.Id );
gp.Color = _BoundaryColor;
gp.Weight = _BoundaryWeight;
gp.Opacity = _BoundaryOpacity;

finally,我们使用了用于将 GMap 控件转换为JavaScript的XSL样式表,将新的GPolyline 边界转换为 JavaScript。 JavaScript被返回到客户端,然后使用 JavaScript eval() 函数执行它。 Viola 我们有一个县边界。 __Show Me__

string path = Server.MapPath("../Scripts/GMap.xsl");
 gpTransform = GXslt.Transform(gp, path, gMap.GetXsltArguments());
 Cache[gm.Id] = gpTransform;
 }
 return gpTransform;
 }
 returnString.Empty;
}

StateQuarters.aspx

__Show Me__

本示例使用 GMap 控件的客户端回调和覆盖数据绑定高级功能。 我使用 GMap 控件设计了美国薄荷 50州程序。 单击表示状态的marker 时,将会看到一些状态信息,以及状态四分之一的图形。 页面本身只是一些样式表信息和 GMap 控件。

<wcp:GMaprunat="server"id="gMap"Width="750px"Height="525px"EnableClientCallBacks="True"OnMarkerClick="gMap_MarkerClick"/>

同样,请注意 EnableClientCallBacksOnMarkerClick 事件处理程序分配。

StateQuarters.aspx.cs

页面加载时,GMap 是以美国为中心的。 以类似于ColoradoCounties示例的方式查询数据库,获取两个字母状态缩写和每个状态的纬度和经度坐标。 这里数据绑定到 GMap,这将导致为每个状态添加一个 marker。 每个 marker的Id 被设置为相应状态的缩写。

gMap.CenterAndZoom(new GPoint(-93.69141F, 40.11169F), 13);
DataSet ds = Cache["States"] as DataSet;if( ds == null )
{
 ds = StateQuarter.GetStates();
 Cache["States"] = ds;
}
gMap.DataSource = ds;
gMap.DataMarkerIdField = "Abbreviation";
gMap.DataLongitudeField = "Longitude";
gMap.DataLatitudeField = "Latitude";
gMap.DataBind();
gMap.AddControl(new GSmallMapControl());

MarkerClick 事件的代码接受单击的marker的Id,并查询数据库以查询完整的状态信息,包括: 州 NAME。州缩写。国家statehood和季度公布的日期。

protectedstring gMap_MarkerClick(object s, GPointEventArgs pea)
{
 GMarker gm = s as GMarker;
 if( gm!= null )
 {
 string gmInfoWindow = Cache[gm.Id] asstring;
 if( gmInfoWindow == null )
 {
 StateQuarter sq = 
 StateQuarter.GetStateQuarterByAbbreviation( gm.Id );

这里数据存储在自定义业务对象中,然后使用 StateQuarter.xsl 样式表进行转换。 转换后的HTML被传递给 GMarker.OpenInfoWindowHtml() 方法。 这里方法创建需要在客户端执行的JavaScript,以便在单击的marker 上打开一个信息窗口。

string path = Server.MapPath("StateQuarter.xsl");
gmInfoWindow =
 gm.OpenInfoWindowHtml(GXslt.Transform(sq, path));

finally,因性能原因而缓存了信息窗口 JavaScript,并返回到实际显示信息窗口的客户端。 __Show Me__

 Cache[gm.Id] = gmInfoWindow;
 }
 return gmInfoWindow;
 }
 returnString.Empty;
}

处理大量标记

我发布关于 谷歌地图 API的最大抱怨之一是,在添加大量标记时,地图变慢了。 对于那些我想说的人。 但是,JavaScript有它的局限性,但我们仍然需要一种方法来表示大量的或者标记。

有一些方法可以做到这一点,包括在某一特定的缩放级别内组合在一起的标记。 这可能成为一个复杂的数学问题( 对于那些比我聪明得多的人)。 ,酒店示例只加载在用户查看范围内的标记,并将它们作为用户的位置移除。 除非你限制用户缩小范围,否则这不会完全解决这个问题。 示例 below 可以扩展为只显示用户查看边界和缩放级别的标记。

AccorHotels.aspx

__Show Me__

这是最复杂的示例,但在你自己的GMap 应用程序中可能是最有用的实现。 首先,我们将从客户端JavaScript开始。 我们实现了三个客户端 GMap 事件,GMap_AddOverlay()GMap_RemoveOverlay()GMap_MoveEnd()。 仅实现添加/删除覆盖,以提供添加和移除标记以及当前查看范围内标记数的视觉指示。 在 GMap_MoveEnd() 中用户完成映射映射时,我们将遍历所有覆盖( 或者标记) 并确定哪一个位于地图的当前边界。 我们删除所有不在查看范围内的。

function GMap_MoveEnd()
{
 var bounds = this.getBoundsLatLng();
 var numOverlays = this.overlays.length;
 for( var i=0; i<numOverlays; i++ )
 {
 var pnt = this.overlays[i].point;
 if( pnt.x <bounds.minX || pnt.y <bounds.minY ||
 pnt.x> bounds.maxX || pnt.y> bounds.maxY )
 this.removeOverlay(this.overlays[i]);
 numOverlays = this.overlays.length;
 }
}

页上的其他代码是样式表信息,一些标签和 GMap 控件声明。 在本例中,除了 MarkerClick 事件之外,我们还响应 MoveEnd 服务器端事件。

<wcp:GMaprunat="server"id="gMap"Width="750px"Height="525px"EnableClientCallBacks="True"OnMarkerClick="gMap_MarkerClick"OnMoveEnd="gMap_MoveEnd"/>

AccorHotels.aspx.cs

Accor酒店的Page_Load() 事件很无聊。 这里唯一做的是加载定制的icon。 蓝色 marker 将添加到地图表示汽车旅馆 6,标准红色 marker 将添加标准的红屋顶酒店。

privatevoid Page_Load(object sender, System.EventArgs e)
{
 GIcon gi = new GIcon();
 gi.Id = "BlueMarker";
 gi.Image = new Uri(Global.BaseUri, 
 ResolveUrl("~/Advanced/blueMarker.png"));
 gMap.Icons.Add(gi);
 gMap.CenterAndZoom(new GPoint(-122.101944F, 37.401944F), 4);
 gMap.AddControl(new GSmallMapControl());
}

每当单击 marker 时,我们使用 marker的Id 搜索具有酒店的NAME 和酒店地址的自定义业务对象。

protectedstring gMap_MarkerClick(object s, GPointEventArgs pea)
{
 GMarker gm = s as GMarker;
 if( gm!= null )
 {
 string gmInfoWindow = Cache[gm.Id] asstring;
 if( gmInfoWindow == null )
 {
 AccorHotel ah = GetHotelByName(gm.Id);

然后转换业务对象并获取显示信息窗口所需的客户端 JavaScript,就像状态区的示例一样。

 gmInfoWindow = gm.OpenInfoWindowHtml(HttpUtility.HtmlDecode( 
 GXslt.Transform(ah, path)));
 Cache[gm.Id] = gmInfoWindow;
 }
 return gmInfoWindow;
 }
 returnString.Empty;
}

GMap_MoveEnd() 事件中开始变得有趣。 这里事件循环遍历所有酒店,并将标记添加到当前地图界面中可以见的每个酒店的地图。 首先,我们创建一个 GOverlays 对象,以临时存储将添加到地图中的新标记。

protectedstring gMap_MoveEnd(object s, GPointEventArgs pea)
{
 GOverlays newMarkers = new GOverlays();

接下来,我们从属性 BoundsLatLng 获取 GMap的当前查看界限。 BoundsLatLng 被转换为 RectangleF 结构。 我们这样做的原因是利用了 RectangleF 中内置的所有功能,比如 Contains()Intersect()Union()。 我们还从前面的GMap_MoveEnd() ( 保存到会话) 调用中获取 BoundsLatLng。 这样做是为了不添加相同的marker 两次。

RectangleF currBounds = gMap.BoundsLatLng.ToRectangleF();
RectangleF prevBounds = PreviousBounds;

现在我们遍历所有酒店,找出 GMap的当前 BoundsLatLng 是否包含酒店所在的点。 如果是,如果以前没有添加 marker,我们将它添加到新标记的List。

foreach( object o in Hotels )
{
 AccorHotel ah = o as AccorHotel;
 PointF currPoint = ah.Marker.Point.ToPointF();
 if( currBounds.Contains(currPoint) )
 {
 if(!prevBounds.Contains(currPoint) )
 newMarkers.Add(ah.Marker);
 }
}

finally,我们使用当前的BoundsLatLng 更新 PreviousBounds,使用 GMap.xsl 样式表将新标记的List 转换为 JavaScript,并将该JavaScript返回到地图。

 PreviousBounds = currBounds;
 if( newMarkers.Count >0 )
 {
 string path = Server.MapPath("../Scripts/GMap.xsl");
 string newOverlays = 
 GXslt.Transform(new GOverlaysWrapper(newMarkers), path, 
 gMap.GetXsltArguments());
 return newOverlays;
 }
 else {
 returnString.Empty;
 }
}

我已经封装了几个基本业务类中的一些功能,但本示例的主要推力是根据当前可以见部分。 你可以下载代码以查看完整的实现。 服务器端 MoveEnd 处理标记的添加,客户端 MoveEnd 处理标记的删除。 __Show Me__

结束语

在本文中,我们介绍了. NET GMap 控件的高级用法。 现在你已经了解了如何使用覆盖数据绑定。客户端回调以及 postback 上关于 GMap的数据,那么你可以在这里找到整洁的应用程序所需的空间。

我将讨论如何设计 GMap 控件,以及如何为我的一些设计决策提供推理。


PAR  控制  FLA  FLAT  Google地图