最近公司用SharpMap作了一个作桌面程序,它是一个开源的Gis项目,功能还能够,最大的特色就是简单易用,这里介绍下怎么在web下使用:javascript
此次咱们根据demo先了解一下如何show一个地图。这是最基本的步骤,也比较简单,但愿能对刚入门的同窗有所帮助。css
咱们使用SharpMap.UI.dll中的ajax控件 <smap:AjaxMapControl width="1600px" Height="600px" id="ajaxMap" runat="server"
OnClickEvent="MapClicked" onmouseout="toolTip();"; OnViewChange="ViewChanged" CssClass="Ly" UseCache="false"
OnViewChanging="ViewChanging" ZoomSpeed="1" /> 来展现地图,主要代码分析以下:html
首先,初始化地图java
public static SharpMap.Map InitializeMap(System.Drawing.Size size) { HttpContext.Current.Trace.Write("Initializing map"); //Initialize a new map of size 'imagesize' SharpMap.Map map = new SharpMap.Map(size); //Set up the countries layer SharpMap.Layers.VectorLayer layCountries = new SharpMap.Layers.VectorLayer("Countries"); //Set the datasource to a shapefile in the App_data folder layCountries.DataSource = new SharpMap.Data.Providers.ShapeFile(HttpContext.Current.Server.MapPath(@"~\App_data\countries.shp"), true); //Set fill-style to green layCountries.Style.Fill = new SolidBrush(Color.Green); //Set the polygons to have a black outline layCountries.Style.Outline = System.Drawing.Pens.Black; layCountries.Style.EnableOutline = true; layCountries.SRID = 4326; //Set up a river layer SharpMap.Layers.VectorLayer layRivers = new SharpMap.Layers.VectorLayer("Rivers"); //Set the datasource to a shapefile in the App_data folder layRivers.DataSource = new SharpMap.Data.Providers.ShapeFile(HttpContext.Current.Server.MapPath(@"~\App_data\rivers.shp"), true); //Define a blue 1px wide pen layRivers.Style.Line = new Pen(Color.Blue,1); layRivers.SRID = 4326; //Set up a river layer SharpMap.Layers.VectorLayer layCities = new SharpMap.Layers.VectorLayer("Cities"); //Set the datasource to a shapefile in the App_data folder layCities.DataSource = new SharpMap.Data.Providers.ShapeFile(HttpContext.Current.Server.MapPath(@"~\App_data\cities.shp"), true); //Define a blue 1px wide pen //layCities.Style.Symbol = new Bitmap(HttpContext.Current.Server.MapPath(@"~\App_data\icon.png")); layCities.Style.SymbolScale = 0.8f; layCities.MaxVisible = 40; layCities.SRID = 4326; //Set up a country label layer SharpMap.Layers.LabelLayer layLabel = new SharpMap.Layers.LabelLayer("Country labels"); layLabel.DataSource = layCountries.DataSource; layLabel.Enabled = true; layLabel.LabelColumn = "Name"; layLabel.Style = new SharpMap.Styles.LabelStyle(); layLabel.Style.ForeColor = Color.White; layLabel.Style.Font = new Font(FontFamily.GenericSerif, 12); layLabel.Style.BackColor = new System.Drawing.SolidBrush(Color.FromArgb(128,255,0,0)); layLabel.MaxVisible = 90; layLabel.MinVisible = 30; layLabel.Style.HorizontalAlignment = SharpMap.Styles.LabelStyle.HorizontalAlignmentEnum.Center; layLabel.SRID = 4326; layLabel.MultipartGeometryBehaviour = SharpMap.Layers.LabelLayer.MultipartGeometryBehaviourEnum.Largest; //Set up a city label layer SharpMap.Layers.LabelLayer layCityLabel = new SharpMap.Layers.LabelLayer("City labels"); layCityLabel.DataSource = layCities.DataSource; layCityLabel.Enabled = true; layCityLabel.LabelColumn = "Name"; layCityLabel.Style = new SharpMap.Styles.LabelStyle(); layCityLabel.Style.ForeColor = Color.Black; layCityLabel.Style.Font = new Font(FontFamily.GenericSerif, 11); layCityLabel.MaxVisible = layLabel.MinVisible; layCityLabel.Style.HorizontalAlignment = SharpMap.Styles.LabelStyle.HorizontalAlignmentEnum.Left; layCityLabel.Style.VerticalAlignment = SharpMap.Styles.LabelStyle.VerticalAlignmentEnum.Bottom; layCityLabel.Style.Offset = new PointF(3, 3); layCityLabel.Style.Halo = new Pen(Color.Yellow, 2); layCityLabel.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; layCityLabel.SmoothingMode = SmoothingMode.AntiAlias; layCityLabel.SRID = 4326; layCityLabel.LabelFilter = SharpMap.Rendering.LabelCollisionDetection.ThoroughCollisionDetection; layCityLabel.Style.CollisionDetection = true; //Add the layers to the map object. //The order we add them in are the order they are drawn, so we add the rivers last to put them on top map.Layers.Add(layCountries); map.Layers.Add(layRivers); map.Layers.Add(layCities); map.Layers.Add(layLabel); map.Layers.Add(layCityLabel); //limit the zoom to 360 degrees width map.MaximumZoom = 360; map.BackColor = Color.LightBlue; map.Zoom = 360; map.Center = new SharpMap.Geometries.Point(0,0); HttpContext.Current.Trace.Write("Map initialized"); return map; }
这段代码中,web
SharpMap.Layers.VectorLayer layCountries = new SharpMap.Layers.VectorLayer("Countries");
layCountries.DataSource = new SharpMap.Data.Providers.ShapeFile(HttpContext.Current.Server.MapPath(@"~\App_data\countries.shp"), true);ajax
这两句话定义并初始化了一个map的一个层。一个map可能包含多个层,咱们对map进行操做,其实就是对map的各个层进行操做,好比说道路层,建筑层等等。根据业务的复杂程度,可能有不少个层。通常来讲,每一个层都有各自的抽象特征(一类对象),能够进行同样的操做。各个层组合起来,就是一个map.网络
好,接着说初始化。这里为VectorLayer的构造函数提供了一个层的名称,然受设置了数据源。一个层的Datasource是一个IProvider类型的数据,而ShapeFile类正是实现了Iprovider接口的类。(这点很重要,之后有不少机会须要把一个datasource转换成ShapeFile)。asp.net
接下来是对这个层进行着色,呵呵 就是这个层上的对象如何填充颜色。这里由于是刚刚开始,咱们就用最简单的办法,设置了一个less
layCountries.Style.Fill = new SolidBrush(Color.Green);ide
这样,就把层上的对象都填充成了绿色。在之后的讲解中,咱们会让你们了解到如何自定义theme,这样咱们能根据实现设置的对象的类型填充不一样的颜色,以实现自定义的样式,让地图多彩多姿。
而后咱们看到label层。每个map的layer都有本身的label层。
SharpMap.Layers.LabelLayer layLabel = new SharpMap.Layers.LabelLayer("Country labels");
layLabel.DataSource = layCountries.DataSource;
layLabel.Enabled = true;
layLabel.LabelColumn = "Name";
这里咱们首先定义了一个label层,而后把countries层的datasource直接赋给label层的datasource就OK了。这样,这个新定义的label层就属于countries层了。而后咱们给它制定一个labelColumn,这个是必须指定的。它表示countries层的每一个对象应该显示什么内容。这个内容在ShapeFile(咱们在MapWindow GIS中创建的shapefile文件)的attribute中进行增长和更新。
我想有必要说一下地图的对象。
地图上有不少点,线和多边形。这些都是对象。咱们均可以对他们进行操做。每一个对象有相应的属性,这些属性咱们也能够添加,修改和删除。而上述的label的LabelColumn就是这些属性中的一个。咱们在这里能够指定一个,也能够经过LabelStringDelegate来委托一个方法返回一个字符串(这个将在之后进行详细讲解)。
OK,在设置了label的字体颜色,大小和背景色以后,有两个个属性是特别值得咱们注意的。
layLabel.MaxVisible = 90;
ayLabel.MinVisible = 30;
这两个值说明了咱们在多大/多小的比例尺下能够看到这个label层。我就常常会忽略这个问题,以致于在放大或缩小比例尺的时候看不到label,也找不到缘由。
在初始化的最后,咱们把全部的层都加到地图中来,在设置一下最大的比例尺,背景色和中心点,就能够了
map.Layers.Add(layCountries);
map.Layers.Add(layRivers);
map.Layers.Add(layCities);
map.Layers.Add(layLabel);
map.Layers.Add(layCityLabel);
//limit the zoom to 360 degrees width
map.MaximumZoom = 360;
map.BackColor = Color.LightBlue;
最后,咱们经过一个maphandler(ashx)把地图输出到页面上。
System.Drawing.Bitmap img = (System.Drawing.Bitmap)map.GetMap();
context.Response.ContentType = "image/png";
System.IO.MemoryStream MS = new System.IO.MemoryStream();
img.Save(MS, System.Drawing.Imaging.ImageFormat.Png);
// tidy up
img.Dispose();
byte[] buffer = MS.ToArray();
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
代码都来自www.codeplex.com/sharpmap的demo。
添加主题 更具一些特性:
private VectorStyle GetCountryStyle(FeatureDataRow row) { VectorStyle style = new VectorStyle(); switch (row["NAME"].ToString().ToLower()) { case "denmark": //If country name is Danmark, fill it with green style.Fill = Brushes.Green; return style; case "united states": //If country name is USA, fill it with Blue and add a red outline style.Fill = Brushes.Blue; style.Outline = Pens.Red; return style; case "china": //If country name is China, fill it with red style.Fill = Brushes.Red; return style; default: break; } //If country name starts with S make it yellow if (row["NAME"].ToString().StartsWith("S")) { style.Fill = Brushes.Yellow; return style; } // If geometry is a (multi)polygon and the area of the polygon is less than 30, make it cyan else if (row.Geometry is IMultiPolygon && (row.Geometry as IMultiPolygon).Area < 30 || row.Geometry is IPolygon && (row.Geometry as IPolygon).Area < 30) { style.Fill = Brushes.Cyan; return style; } else //None of the above -> Use the default style return null; }
在通过第一篇的简单学习以后,咱们开始了解一些稍微有点儿意思的东西,进一步掌握和学习利用sharpmap进行开发的技巧。
此次,咱们主要是跟你们一块儿学习一下如何根据地图上的一个点,来查询这个点所在的对象的信息,并显示到点击的位置。这很是有用,好比说一个想把一个房子显示在地图上,咱们用鼠标一点,便知道这个房子里住的什么人,干什么的,以及其它相关信息。
一样的,咱们仍是使用sharpmap提供的ajax控件,环境和第一篇如出一辙。可是这里,咱们要引用一个叫作NetTopologySuite的类库。它常常和SharpMap一块儿使用,此次咱们只使用其中的一个小部分,废话很少说,开始作。
这里咱们使用asp.net ajax 1.0,首先引用了dll,而且拖上scripmanager并设置为EnablePageMethods=true,这样咱们就能够在页面中写静态方法来实现AJAX。
在MapClicked方法(AjaxMapControl控件提供的方法,直接写在js中便可,表示单击的时候发生一些事情)中,咱们调用咱们写的js,根据两个点来返回一个字符串。这个字符串就是拼好的html,直接显示出来。
这个方法里面的SharpMap_GetRelatiovePosition和 SharpMap_PixelToMap方法根据鼠标在屏幕上的坐标计算出鼠标点在地图上的坐标,再调用咱们本身写的GetData方法便可。在GetData方法中,咱们使用了PageMethods来调用一个后台方法,并返回一个字符串。
PageMethods.GetData(x, y, GetDataSuccess);
而后,在GetDataSuccess中调用一个写好的用来显示这些返回数据的方法(此方法来自网络,js源码以下)。
须要指出的是,这个效果须要作一些初始化的工做:
<div id="toolTipLayer" style="position:absolute;visibility: hidden;z-index:10000">
</div>
<script type="text/javascript">
initToolTips();
</script>
这样,咱们在前台的工做就基本完成了。
固然,若是想要更好看一些,再写一个css帮助从后台传来的html进行淡化。
.clarity
{
filter:alpha(opacity=80,Style=0);
}
OK,如今转去后台。
在根据两个点查询对象数据时,咱们首先要初始化须要初始化shapefile,也就是你要查询的那个层的数据源。
new SharpMap.Data.Providers.ShapeFile(filepath true);
而后遍历shapefile里面的每个feature,对比传入的点和feature所在的Geometry,若是传入的点在feature所在Geometry以内(within方法)的话,就读取当前feature的一个attribute(一般是某个业务对象的ID),这样,根据这个ID就能取到业务对象的值,而后Build一下HTML,返回就OK了。主要代码以下:
这里把sharpfile的Geometry都转换成了NTS 的,这样,使用NTS的Within方法进行比较。sharpmap本身的方法在个人测试中是不能用的,但愿你们在使用过程当中作些尝试,看看是不是我本身的代码有问题,总之,我是用的NTS。
到这里,咱们就实现了根据点来查询对象数据的功能,咱们只须要在shapefile中存储一个attribute(好比对象的ID),而后取出来显示出去就OK了。
同理的,咱们也能够实现根据一个用户ID来找到这个对象在地图中的位置,并显示在地图中间。
代码以下:
找到这个点以后,设置一下控件的地图的中心点,就OK了。
ajaxMap.Map.Center = pCenter;
虽然东西很简单,可是仍是费了我不少功夫。很大一部分缘由是由于sharpmap本身提供的方法不太完善,致使不少时间花费在了追踪问题上。不过这种追踪对理解开源的代码也是颇有好处的。
在这个例子中,我使用了遍历地图中全部feature的方法来定位一个对象,这样很是的耗费资源,效率并很差。若是地图对象比较少还能够,一旦超过必定的数量级,可能会出现性能问题。之后我会在这个基础上进行改进,利用其它方法来实现这个功能(事实上我已经进行了一些尝试,只是尚未成功。若是有人成功了,但愿给我一些建议,谢谢)。
今天就到这里,感谢你们的关注,但愿多多拍砖,共同进步。
在下一篇中,我将和你们共同窗习关于根据attribute的值来填充地图上对象的颜色,设置他们的样式以及一些有趣的小玩意儿。但愿你们继续关注,谢谢。
天天学一天,天天都会进步一点儿。
我写的东西内容浅显,但愿能给初学者一些帮助。至于深刻研究sharpmap和GIS技术的大牛,请不吝赐教,给咱们这些菜鸟多一些指导。
今天咱们接着来聊sharpmap的基本使用技巧,根据attribute来填充地图对象的颜色,让用户更清晰的看到重点的业务对象对应在地图上的表示,以及如何自定义label层的显示内容,字体的大小等。因此,今天的主题主要是自定义:自定义theme,自定义label以及label字体。
首先,咱们要为地图填充上不一样的色彩,让他们看起来五光十色,容易分辨。好比河流和湖泊要填成蓝色,草地要填充上绿色,房子要填充上白色,道路要填充上青色等等。怎么作呢?很简单,先看下代码:
SharpMap.Rendering.Thematics.CustomTheme iTheme = new SharpMap.Rendering.Thematics.CustomTheme(GetMyStyle);
在初始化Map的时候,加上上面的一行代码。它定义了一个自定义的Theme对象,这个对象的构造函数须要传入一个咱们本身写的方法(委托),这个方法里面具体说明了这个 theme是如何定义的,方法代码以下:
这段简单代码你们都看得懂,这个委托定义须要传入一个FeatureDataRow,它的做用就是在初始化地图的过程当中,每处理一个对象,都要到这个方法中来考察一下feature的值是多少以决定具体要填充哪些颜色。在这里,当status为available时,就填充黄色,不然就填充绿色。定义的VectorStyle用来返回给地图。是否是很简单呢?
地图填充完了,咱们要在上面显示出到底他们是什么。在第一篇中,咱们已经能够把对象的一个属性显示出来,可是当地图扩大到必定比例时,仅仅显示名字这一种信息已经不足以知足用户的须要了。好比说一栋房子,在很远处看它时,咱们只须要看到他的颜色就好了。可是当咱们离的很近的时候,难道看到的是全白色吗?显然不是,咱们还能够看到门牌号,窗户上的贴纸以及其它详细信息。地图也同样,当比例尺改变之后,应该有更详细的信息被列出来。老规矩,先贴代码:
SharpMap.Layers.LabelLayer myLabel = new SharpMap.Layers.LabelLayer("labels");
myLabel .DataSource = myLayer.DataSource;
myLabel.LabelStringDelegate= new SharpMap.Layers.LabelLayer.GetLabelMethod(GetLabelString);
在这里,首先定义了一个label(就像在初始化地图里同样,或者就在初始化地图里作),而后把你所要显示的图层的数据源赋值给这个label的数据源,接着为label层的LabelStringDelegate指定一个方法(这个方法传入一个FeatureDataRow,返回一个字符串),最后去实现这个方法,代码以下:
代码简单的要死,再也不详述,值得注意的是:若是要换行,请使用“\r\n”, 这里不支持html拼的字符串。哈,又解决一个问题。爽吧?
而后,新的问题又来了,字体一直都是那么大,或者一直都是那么小,这可怎么办呢?看起来也至关不舒服啊。若是字体能随着比例尺的变化而变化就行了。这个没问题,咱们立刻就搞定它。看代码:
这个方法传入了一个Zoom值和一个ILayer,没有返回值,直接修改ILayer就能够了。
相信你们都看得懂吧?值得注意的问题是:AjaxMap上面的map对象有个属性叫作zoomAmount,这是个javascript的属性须要在前台指定,它说明了地图放大或缩小的比例尺倍数。Demo中是在RadioButtonList的ListItem中指定的。这个过程是这样的:当点击Zoom In这个button,自动执行了一段javascript:
ajaxMapObj.disableClickEvent(); ajaxMapObj.zoomAmount = 3;
而后当咱们点击地图,click事件已经被禁止,系统刷新地图,此时在handler里接受到了地图的新的参数(zoom等),而后从新绘制了地图。因此,咱们在handler里取得zoom参数,而且使用GetLayerByName(“”)方法来取得label层
ChangeFontSize(Zoom, map.GetLayerByName("mylabels"));
这样,就实现了字体随着比例尺变化儿变化。有同窗可能问:那如何让label的内容随着比例尺变化而变化呢?只须要把刚才那句话
myLabel.LabelStringDelegate= new SharpMap.Layers.LabelLayer.GetLabelMethod(GetLabelString);
放到相应的if。。。else语句里就好了。简单吧?
今天就到这里。
这些都是些小技巧,在大牛眼里也许不值一提,可是我但愿能给初学者带来一些帮助,但愿你们工做愉快,每天好心情。
最后欢迎拍砖。