在经过第一篇的简单学习之后,我们开始了解一些稍微有点儿意思的东西,进一步掌握和学习利用sharpmap进行开发的技巧。

  这次,我们主要是跟大家一起学习一下如何根据地图上的一个点,来查询这个点所在的对象的信息,并显示到点击的位置。这非常有用,比如说一个想把一个房子显示在地图上,我们用鼠标一点,便知道这个房子里住的什么人,干什么的,以及其它相关信息。

  同样的,我们还是使用sharpmap提供的ajax控件,环境和第一篇一模一样。但是这里,我们要引用一个叫做NetTopologySuite的类库。它经常和SharpMap一起使用,这次我们只使用其中的一个小部分,废话不多说,开始做。

  这里我们使用ASP.net ajax 1.0,首先引用了dll,并且拖上scripmanager并设置为EnablePageMethods=true,这样我们就可以在页面中写静态方法来实现AJAX。

  在MapClicked方法(AjaxMapControl控件提供的方法,直接写在js中即可,表示单击的时候发生一些事情)中,我们调用我们写的js,根据两个点来返回一个字符串。这个字符串就是拼好的html,直接显示出来。

   function MapClicked(event,obj)
    {
      var mousePos = SharpMap_GetRelativePosition(event.clientX,event.clientY,obj.container);
      var pnt = SharpMap_PixelToMap(mousePos.x,mousePos.y,obj);
      var field = document.getElementById('dataContents');
      //field.innerHTML = "You clicked map at: " + pnt.x + "," + pnt.y;
      GetData(pnt.x, pnt.y);
    }

  这个方法里面的SharpMap_GetRelatiovePosition和 SharpMap_PixelToMap方法根据鼠标在屏幕上的坐标计算出鼠标点在地图上的坐标,再调用我们自己写的GetData方法即可。在GetData方法中,我们使用了PageMethods来调用一个后台方法,并返回一个字符串。

PageMethods.GetData(x, y, GetDataSuccess);

  然后,在GetDataSuccess中调用一个写好的用来显示这些返回数据的方法(此方法来自网络,js源码如下)。

<script type="text/JavaScript">
<!--
    var ns4 = document.layers;
    var ns6 = document.getElementById && !document.all;
    var ie4 = document.all;
    offsetX = 0;
    offsetY = 20;
    var toolTipSTYLE = "";
    function initToolTips() {
        if (ns4 || ns6 || ie4) {
            if (ns4) toolTipSTYLE = document.toolTipLayer;
            else if (ns6) toolTipSTYLE = document.getElementById("toolTipLayer").style;
            else if (ie4) toolTipSTYLE = document.all.toolTipLayer.style;
            if (ns4) document.captureEvents(Event.MOUSEMOVE);
            else {
                toolTipSTYLE.visibility = "visible";
                toolTipSTYLE.display = "none";
            }
            document.onclick = moveToMouseLoc;
        }
    }
    function toolTip(msg, fg, bg) {
        if (toolTip.arguments.length < 1) // hide
        {
            if (ns4) toolTipSTYLE.visibility = "hidden";
            else toolTipSTYLE.display = "none";
        }
        else // show
        {
            if (!fg) fg = "#777777"; //fore color
            if (!bg) bg = "#FFFFFF"; //bg color
            var content = msg;
            if (ns4) {
                toolTipSTYLE.document.write(content);
                toolTipSTYLE.document.close();
                toolTipSTYLE.visibility = "visible";
            }
            if (ns6) {
                document.getElementById("toolTipLayer").innerHTML = content;
                toolTipSTYLE.display = 'block'
            }
            if (ie4) {
                document.all("toolTipLayer").innerHTML = content;
                toolTipSTYLE.display = 'block'
            }
        }
    }
    function moveToMouseLoc(e) {
        if (ns4 || ns6) {
            x = e.pageX;
            y = e.pageY;
        }
        else {
            x = event.x + document.body.scrollLeft;
            y = event.y + document.body.scrollTop;
        }
        toolTipSTYLE.left = x + offsetX;
        toolTipSTYLE.top = y + offsetY;
        return true;
    }
    //-->
    </script>

  需要指出的是,这个效果需要做一些初始化的工作:

   <div id="toolTipLayer" style="position:absolute;visibility: hidden;z-index:10000">
    </div>
    <script type="text/JavaScript">
        initToolTips();
    </script>

  这样,我们在前台的工作就基本完成了。

  当然,如果想要更好看一些,再写一个css帮助从后台传来的html进行淡化。

 .clarity
        {
            background-color:#4d7d99;
            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了。主要代码如下:

  

  public string GetInfo(double x, double y)
        {
            SharpMap.Data.Providers.ShapeFile oShape = (SharpMap.Data.Providers.ShapeFile)GetShapeFile(filepath);
            if (!oShape.IsOpen)
            {
                oShape.Open();
            }

            uint iFeature = (uint)oShape.GetFeatureCount();

            SharpMap.Geometries.Point oPoint = new SharpMap.Geometries.Point(x, y);
            GISSharPBlog.netTopologySuite.Geometries.Geometry oPt = SharpMap.Converters.NTS.GeometryConverter.ToNTSGeometry(oPoint, new GisSharpBlog.NetTopologySuite.Geometries.GeometryFactory());
            StringBuilder sb = new StringBuilder();
            // find a record
            string graveInfo = string.Empty;
            for (uint i = 0; i < iFeature; i++)
            {
                GisSharpBlog.NetTopologySuite.Geometries.Geometry oPoly = SharpMap.Converters.NTS.GeometryConverter.ToNTSGeometry(oShape.GetFeature(i).Geometry, new GisSharpBlog.NetTopologySuite.Geometries.GeometryFactory());
                if (oPt.Within(oPoly))
                {
                    if (oShape.GetFeature(i)[someId].ToString().Length > 0)
                    {
                        return BuildGraveInfoTable(name, value);
                    }
                }

            }

            return string.emtpy;
        }

  这里把sharpfile的Geometry都转换成了NTS 的,这样,使用NTS的Within方法进行比较。sharpmap自己的方法在我的测试中是不能用的,希望大家在使用过程中做些尝试,看看是否是我自己的代码有问题,总之,我是用的NTS。

  到这里,我们就实现了根据点来查询对象数据的功能,我们只需要在shapefile中存储一个attribute(比如对象的ID),然后取出来显示出去就OK了。

  同理的,我们也可以实现根据一个用户ID来找到这个对象在地图中的位置,并显示在地图中间。

  代码如下:

  

  public SharpMap.Geometries.Point GetPointByID(string Id)
        {
            SharpMap.Data.Providers.ShapeFile oShape = (SharpMap.Data.Providers.ShapeFile)GetShapeFile(filePath);
            oShape.Open();
            uint i = 0;
            uint iFeature = (uint)oShape.GetFeatureCount();

            SharpMap.Geometries.Point oPt = null;
            for (i = 0; i < iFeature; i++)
            {
                GISSharPBlog.netTopologySuite.Geometries.Geometry oPoly = SharpMap.Converters.NTS.GeometryConverter.ToNTSGeometry(oShape.GetFeature(i).Geometry, new GisSharpBlog.NetTopologySuite.Geometries.GeometryFactory());

                if (oShape.GetFeature(i)["Id"].ToString() == Id)
                {
                    oPt = new SharpMap.Geometries.Point(oPoly.InteriorPoint.X, oPoly.InteriorPoint.Y);
                }
            }

            return oPt;
        }

 

  找到这个点之后,设置一下控件的地图的中心点,就OK了。

   ajaxMap.Map.Center = pCenter;

  虽然东西很简单,但是还是费了我很多功夫。很大一部分原因是因为sharpmap自己提供的方法不太完善,导致很多时间花费在了追踪问题上。不过这种追踪对理解开源的代码也是很有好处的。

  在这个例子中,我使用了遍历地图中所有feature的方法来定位一个对象,这样非常的耗费资源,效率并不好。如果地图对象比较少还可以,一旦超过一定的数量级,可能会出现性能问题。以后我会在这个基础上进行改进,利用其它方法来实现这个功能(事实上我已经进行了一些尝试,只是还没有成功。如果有人成功了,希望给我一些建议,谢谢)。

  今天就到这里,感谢大家的关注,希望多多拍砖,共同进步。

  在下一篇中,我将和大家共同学习关于根据attribute的值来填充地图上对象的颜色,设置他们的样式以及一些有趣的小玩意儿。希望大家继续关注,谢谢。

posted on 2012-12-18 16:29  骑牛射雕  阅读(396)  评论(0编辑  收藏  举报