概述(一)
开始,当然是下载并安装MapXtreme 2005,双击exe后一路next下去,完成.
然后,打开VS 2005,新建项目里,就有MapXtreme项目,
如果,有iis,MapXtreme默认会在iis里新建很多虚拟目录,对应安装目录下的示例工程
接下来就有一系列的事情要处理了
1.配置webconfig,如果不知道怎么配置,新建一个MapXtreme项目,然后打开里面的webconfig,对照一下该copy的copy就行了
2.找资料:上博客园,上百度,上google,搜啊搜
就我的搜索而言:在博客园里搜了一些,都是些代码,一开始看着头大
打开安装目录下,一般是:C:\Program Files\MapInfo\MapXtreme\6.7.1
发现里面东西挺多的:有文档,样例,工具和指南.
是一些示例和文档,文档还是E文的,还是一个头两个大
3.看你所有文档,理解一些相关知识:Catalog,TableInfo,Table,Feature,Geometry,Style
4.运行示例,进入Hello world世界
5.把博客园的资料代码copy过去,先弄个点,线出来,满足下心理需求
6.看多个示例代码,找出共同点
7.添加工具,把工具拉到界面并使用看看
8.自己按示例,弄个自定义的WebTool出来
9.打开控件源码,理解是怎么接收请求和输出,源码在:C:\Program Files\MapInfo\MapXtreme\6.7.1\Samples\WebControlsSourceCode
10.打开资源中的三个js,分别是Interaction,Command,Tool,理解三个是怎么发送请求
11.实现自已要的功能
了解新建MapXtreme项目结构(二)
首先,打开VS2005,新建网站,选择MapXtreme 6.7.1 Web Application
新建好后,发现网站目录下关键结构如下:
1.App_Code文件夹:有一个自定义的AppStateManager.cs类,继承自StateManager,主要是实现自定义的地图保存与还原,地图都存在Session中的,而且还是序列化成二进制存进去的
2.MapXtremeWebResources文件夹:主要有几个关键的js,比如:
Interaction.js,交互用的js,比如是实现点击,双击,还是鼠标移动,还是画圈之类的.
Command.js,发送命令用的,比如是GetMap,请求一个地图,还是ZoomOut放大地图,或是ZoomIn缩小地图
Tool.js,就是界面上拉的那些控件工具用的,比如点击一个控件,才能引发相应的点击,并发送命令
3.Global.asax:主要是一些地图出错后的处理
4.MapForm.aspx:主要的示例界面,里面拖了一个地图显示控件,和一些工具控件在里面
后台有几句代码,主要是用于访问时,初始化状态管理,并还原地图显示;退出时,就保存地图当前的状态
5.Web.Config:相关的地图配置
<add key="MapInfo.Engine.Session.Pooled" value="true" />是否开启Session池,一般都开了
<add key="MapInfo.Engine.Session.State" value="Manual" />
有两个选项HttpSessionState和Manual
HttpSessionState时,系统自动管理地图的保存
Manual时,手动来决定是否保存用户状态了。就像页面退出时,调了个方法,来手动保存地图状态
<add key="MapInfo.Engine.Session.Workspace" value="C:\Program Files\MapInfo\MapXtreme\6.7.1\Samples\Data\World.mws;c:\Program Files (x86)\MapInfo\MapXtreme\6.7.1\Samples\Data\World.mws" />
地图的工作空间,可以有多个,用“,”号分隔。有一个MapFactory[索引]来取相应的地图
一般都是通过地图别名来取,很奇怪的我这里就是用别名取不到,只能取MapFactory[0]即第一个
所以一般工作空间就一个了
可以参考自C:\Program Files\MapInfo\MapXtreme\6.7.1\Documentation\PDF\MapXtreme2005_DevGuide.pdf中的文档第六章中的A Detailed Look at Manual State Management下的Application Settings即关于webconfig的说明
<assemblies>程序集</assemblies>:没啥说的,copy就行
<httpHandlers>和<httpModules>:处理请求用的
<sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" cookieless="false" timeout="20" />
这个就是Sesstion是保存到数据库中的了,和以往的InProc不一样了
所以相关的地方就是当你要用到Session的时候,存的东西必即是可序列化的,不然就报错了
比如HttpContext.Session[实体类],如果实体类不是可序列化的,就报错了
相关代码知识(三)
在看代码之前,先来了解下简单的代码知识:
1.MapFactory[索引或地图别名]:简单理解为存放地图的容器,要地图就来这里取
相关代码:MapInfo.Mapping.Map myMap = MapInfo.Engine.Session.Current.MapFactory[索引或地图别名];
2.Map:地图,里面有很多东西,比如坐标体系,很多张图层(Layers),还多个图元(Legends);
相关代码:取图层,myMap.Layers[图层名];取图元,myMap.Legends[图元名]
3.FeatureLayer:图层,Layer的一种,和ps图片一样,一个图层里可以放很多个点,对应一张数据表
相关代码:FeatureLayer feaLayer=(MapInfo.Mapping.FeatureLayer)myMap.Layers[图层名];
4.TableInfo:表信息,包括表名,和列的添加都在这里,可以通过信息,创建一个Table,只是有两个列,是必备的
一个是Geometry列:存放的图型类别,如:是点,还是线,还是其它,(坐标在创建点或线的时候就有写在里面了)
一个是Style列,存放的是图形类别的样式,如:点的颜色,点的形状。线的宽度之类的
其它的列,就自己根据需要了创建了
5.Table:数据表,对应一个图层。可以放很多行,和常见的表一样,
相关代码:
创建表:Table table= MapInfo.Engine.Session.Current.Catalog.CreateTable(TableInfo);
获取表:Table table= MapInfo.Engine.Session.Current.Catalog.GetTable(表名);
也可通过图层来取,如果已先关联的话了:
FeatureLayer feaLayer=(MapInfo.Mapping.FeatureLayer)myMap.Layers[图层名];
Table table=feaLayer.Table;
6.Catalog,简单说就是类似一个DataSet的东西,里面可以放很多的表
相关代码:MapInfo.Data.Table tb= MapInfo.Engine.Session.Current.Catalog.GetTable(表名);
7.Feature,可以放进图层里的东西,简单的说是应数据的行,行是列组成的,所以实例化是需要传进表格的列
相关代码:MapInfo.Data.Feature point = new MapInfo.Data.Feature(table.TableInfo.Columns);
把Feature放进Layer里:Table.InsertFeature(point ) ;
--------------------------------------------------------
相关的联想如下:
FeatureLayer和Feature:FeatureLayer是一个层,而Feature只是层上面的一个点(一点就一行数据),或一条线之类的
行是由列组成的,所以创建行时,构造函数要传入列集合:
MapInfo.Data.Feature ptPoint = new MapInfo.Data.Feature(table.TableInfo.Columns);
数据层面:有一个Feature行,行就只能放入表Table,表又放Catalog里
所以行添加就Table.InsertFeature(行);
地图层面:有一个FeatureLayer图层,点要放入图层集Layers里,图层要放入Map里,Map又放入MapFactory里
图层关联Table,Table 有很多行数据.所以就有可能有很多点(一行数据一个点),可能有很多线(一行数据一条线)
把图层放入图层集里就是Layers.Add(图层);
把图层集属于地图,所以才有Map.Layers.Add(图层);
一些基础函数代码(四)
网上看到的基本上代码都大同小异,经过本人小小修改或未修改的代码如下:
一:先创建图层
创建图层函数代码:
/** <summary>
/// 创建临时图层
/// by 路过秋天
/// <param name="tableName">表名</param>
/// <param name="layerName">图层名</param>
/// </summary>
public static void CreateLayer(string tableName, string layerName)
{
MapInfo.Mapping.Map myMap = MapInfo.Engine.Session.Current.MapFactory[0];//取得当前地图
//建立内存表信息(TableInfo中的一种,所以当然还有其它很多种表类型)
MapInfo.Data.TableInfoMemTable tblInfo = new MapInfo.Data.TableInfoMemTable(tableName);
//向表信息中添加可绘图列(必备的列)
tblInfo.Columns.Add(MapInfo.Data.ColumnFactory.CreateFeatureGeometryColumn(myMap.GetDisplayCoordSys()));
tblInfo.Columns.Add(MapInfo.Data.ColumnFactory.CreateStyleColumn());
//向表信息中添加其它数据列(可选的列)
tblInfo.Columns.Add(MapInfo.Data.ColumnFactory.CreateIntColumn("index"));//创建整形的列,当然还有其它日期型的,doule型的等等
tblInfo.Columns.Add(MapInfo.Data.ColumnFactory.CreateStringColumn("value", 20));//创建字符串型的列,并指定长度
//确保当前目录下不存在同名表
MapInfo.Data.Table table = MapInfo.Engine.Session.Current.Catalog.GetTable(tableName);
if (table != null)
{
MapInfo.Engine.Session.Current.Catalog.CloseTable(tableName);
}
//根据表信息创建临时表
table = MapInfo.Engine.Session.Current.Catalog.CreateTable(tblInfo);
//创建图层(并关联表)
FeatureLayer tempLayer = new FeatureLayer(table, layerName, layerName);
myMap.Layers.Add(tempLayer);
}
二:在图层的基础上,创建点,线,或其它图型
创建点函数代码:
/** <summary>
/// 添加点
/// by 路过秋天
/// </summary>
/// <param name="layerName">图层名称</param>
/// <param name="dPoint">点的坐标</param>
/// <param name="shortCode">点的代码,不同的数字有不同的形状(圆型,三角型,正方型等)</param>
/// <param name="color">点的颜色</param>
public static void AddPoint(string layerName, DPoint dPoint, short shortCode, Color color)
{
MapInfo.Mapping.Map myMap = MapInfo.Engine.Session.Current.MapFactory[0];
//获取图层和表
FeatureLayer workLayer = (MapInfo.Mapping.FeatureLayer)myMap.Layers[layerName];
MapInfo.Data.Table table = workLayer.Table;
//创建点
FeatureGeometry point = new MapInfo.Geometry.Point(workLayer.CoordSys, dPoint);
//以下两行是图形的样式
MapInfo.Styles.SimpleVectorPointStyle spsPoint = new MapInfo.Styles.SimpleVectorPointStyle(shortCode, color, 20);
MapInfo.Styles.CompositeStyle pointStyle = new MapInfo.Styles.CompositeStyle(spsPoint);
//接下来创建一行数据
MapInfo.Data.Feature pointRow = new MapInfo.Data.Feature(table.TableInfo.Columns);
pointRow.Geometry = point;//必备列[图形]
pointRow.Style = pointStyle;//必备列[图形样式]
pointRow["index"] = new Random().Next(999);
pointRow["value"] = "this is a point";
//将一行数据放入表中
table.InsertFeature(pointRow);
}
关于shortCode:
参考C:\Program Files\MapInfo\MapXtreme\6.7.1\Documentation\PDF\MapXtreme2005_DevGuide.pdf
下的Appendix G:Style Lookups(附录G,样式查找)下的Vector Symbols(矢量符号)->Map Symbols (地图符号)
创建线函数代码:
/** <summary>
/// 添加线[代码和创建点的相差无几]
/// by 路过秋天
/// <param name="layerName">图层名</param>
/// <param name="startPoint">线段起点坐标</param>
/// <param name="endPoint">线段终点坐标</param>
/// <param name="shortCode">线的shortCode(线的型状也有多种,比如单箭头,双箭头等)</param>
/// <param name="color">线的颜色</param>
/// </summary>
public static void AddLine(string layerName, DPoint startPoint, DPoint endPoint, int shortCode, Color color)
{
MapInfo.Mapping.Map myMap = MapInfo.Engine.Session.Current.MapFactory[0];
//获取图层和表
FeatureLayer workLayer = (MapInfo.Mapping.FeatureLayer)myMap.Layers[layerName];
MapInfo.Data.Table table = workLayer.Table;
//创建线
FeatureGeometry line = MultiCurve.CreateLine(workLayer.CoordSys, startPoint, endPoint);
//以下两行是图形的样式
MapInfo.Styles.SimpleLineStyle slsLine = new MapInfo.Styles.SimpleLineStyle(new LineWidth(3, LineWidthUnit.Pixel), shortCode, color);
MapInfo.Styles.CompositeStyle lineStyle = new MapInfo.Styles.CompositeStyle(slsLine);
//接下来创建一行数据
MapInfo.Data.Feature ptLine = new MapInfo.Data.Feature(table.TableInfo.Columns);
ptLine.Geometry = line;
ptLine.Style = lineStyle;
ptLine["index"] = new Random().Next(999); ;
ptLine["value"] = "this is a line";
//将线图元加入图层
table.InsertFeature(ptLine);
}
三:显示标注文本
显示标注文本函数代码:
/** <summary>
/// 显示标注
/// by 路过秋天
/// <param name="tableName">标注的表名</param>
/// <param name="columnName">标注的列名</param>
/// </summary>
public static void ShowValue(string tableName, string columnName)
{
MapInfo.Mapping.Map myMap = MapInfo.Engine.Session.Current.MapFactory[0];
//新建标注图层并绑定数据(整个过程有点像DataGrid控件指定数据源控件SqlDataSource,而数据源控件又绑定了DataTable)
LabelLayer labelLayer = new LabelLayer();
myMap.Layers.Add(labelLayer);
//指定要标注的数据表
MapInfo.Data.Table table = MapInfo.Engine.Session.Current.Catalog.GetTable(tableName);
LabelSource source = new LabelSource(table);//绑定Table
labelLayer.Sources.Append(source);//加载指定数据
//指定哪个字段作为显示标注(在非必备的自定义列里挑一个,比如我们就挑"value"列)
source.DefaultLabelProperties.Caption = columnName;
//标注样式等属性,注意这段注释的代码,是指在一定的缩放比例范围内才显示文本,要是不注释掉,可能折腾半天也看不到为啥显示不出来文本
//source.DefaultLabelProperties.Visibility.Enabled = true;
//source.DefaultLabelProperties.Visibility.VisibleRangeEnabled = true;
//source.DefaultLabelProperties.Visibility.VisibleRange = new VisibleRange(0.01, 10, MapInfo.Geometry.DistanceUnit.Mile);
source.DefaultLabelProperties.Visibility.AllowDuplicates = true;
source.DefaultLabelProperties.Visibility.AllowOverlap = true;
source.DefaultLabelProperties.Visibility.AllowOutOfView = true;
source.Maximum = 50;
source.DefaultLabelProperties.Layout.UseRelativeOrientation = true;
source.DefaultLabelProperties.Layout.RelativeOrientation = MapInfo.Text.RelativeOrientation.FollowPath;
source.DefaultLabelProperties.Layout.Angle = 33.0;
source.DefaultLabelProperties.Layout.Offset = 7;
source.DefaultLabelProperties.Layout.Alignment = MapInfo.Text.Alignment.CenterCenter;
MapInfo.Styles.Font font = new MapInfo.Styles.Font("黑体", 12);
font.ForeColor = System.Drawing.Color.Red;
source.DefaultLabelProperties.Style.Font = font;
}
先上这四个最基本的函数,如果把这几个函数放一个类中,别忘了加名称空间:
using MapInfo.Geometry;
using MapInfo.Mapping;
using MapInfo.Styles;
using MapInfo.Data;
using MapInfo.Text;
using System.Drawing;
在地图上创建点/线并显示标注(五)
新建一个网站,选择MapXtreme 6.7.1 Web Application
在App_Code中,我们新建一个类,起名叫:LayerManager.cs
然后,把上一节的函数代码全copy过来,还有using的名称空间
打开MapForm.aspx的后台代码
在原有的Page_Load代码里,添加如下代码:
string tableName = "tableName", layerName = "layerName";//随便定义两个名字
LayerManager.CreateLayer(tableName, layerName);//创建图层
LayerManager.AddPoint(layerName, GetDPoint(60,60), 35, Color.Red);//创建一个红色五角星的点
LayerManager.AddLine(layerName, GetDPoint(160, 160), GetDPoint(300, 160), 59, Color.Red);//创建一条红色单箭头的线
LayerManager.ShowValue(tableName, "value");//显示标注
里面有一个GetDPoint(int x,int y)函数,主要是传入客户端的坐标,返回地图的经纬度
函数如下:
private DPoint GetDPoint(int x,int y)
{
DPoint dp = new DPoint();
System.Drawing.Point point = new System.Drawing.Point(x, y);//客户端坐标(相对地图)
Map map = MapInfo.Engine.Session.Current.MapFactory[0];
map.DisplayTransform.FromDisplay(point, out dp);//转成相应的经纬度坐标
return dp;
}
完成后的页面代码如下:
public partial class _Default : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
// If the StateManager doesn't exist in the session put it else get it.
if (StateManager.GetStateManagerFromSession() == null)
StateManager.PutStateManagerInSession(new AppStateManager());
// Now Restore State
StateManager.GetStateManagerFromSession().ParamsDictionary[StateManager.ActiveMapAliasKey] = MapControl1.MapAlias;
StateManager.GetStateManagerFromSession().RestoreState();
string tableName = "tableName", layerName = "layerName";//随便定义两个名字
LayerManager.CreateLayer(tableName, layerName);//创建图层
LayerManager.AddPoint(layerName, GetDPoint(60,60), 35, Color.Red);//创建一个红色五角星的点
LayerManager.AddLine(layerName, GetDPoint(160, 160), GetDPoint(300, 160), 59, Color.Red);//创建一条红色单箭头的线
LayerManager.ShowValue(tableName, "value");//显示标注
}
private DPoint GetDPoint(int x,int y)
{
DPoint dp = new DPoint();
System.Drawing.Point point = new System.Drawing.Point(x, y);//客户端坐标(相对地图)
Map map = MapInfo.Engine.Session.Current.MapFactory[0];
map.DisplayTransform.FromDisplay(point, out dp);//转成相应的经纬度坐标
return dp;
}
// At the time of unloading the page, save the state
private void Page_UnLoad(object sender, System.EventArgs e)
{
StateManager.GetStateManagerFromSession().SaveState();
}
}
OK,保存,浏览,即可在页面上看到在相应的地方上,创建了一个五角星和一个红色单向箭头线.
工具(六)
在新建的项目中,我们看示例的MapForm.aspx页面上的html代码
上面放了N个工具:
<cc1:MapControl ID="MapControl1" runat="server" Height="248px" Width="393px" MapAlias="Map1" />
地图显示工具,最图生成的标签为<span><img src='MapController.ashx?Command=getmap&..' /></span>的形式
简单说就是由MapController.ashx以流方式输出一张图片,和验证验的输出差不多
所有的请求都是通过客户端ajax请求发出的,MapController.ashx根据请求的Command类型,输出图片流,或直接输出字符串.比如:
Command类型为放大缩小图片或拖动图片时,返回的就是图片流。其结果表现为更新img的src
如果请求的类型是求两点的距离,那只要返回字符串就行,不需要更新图片,其结果可能alert(xmlHttp.responseText)
所有的请求都是先激活工具,再触发相应的事件,然后以ajax方式发送请求到MapController.ashx处理
其它主要工具为:一个共同属性:MapControlID指定作用于哪个地图控件
1.地图缩放比例工具
<cc1:ZoomBarTool ID="ZoomBarTool1" runat="server" ZoomLevel="500" MapControlID="MapControl1" />
ZoomLevel的值,决定了缩放的比例,默认单位是kilometer(公里)
2.方向移动工具,8个,对应八个方位,没啥可说的
<cc1:NorthWestNavigationTool ID="NorthWestNavigationTool1" runat="server" MapControlID="MapControl1" />
3.放大和缩小工具
<cc1:ZoomOutTool ID="ZoomOutTool1" runat="server" MapControlID="MapControl1" />
<cc1:ZoomInTool ID="ZoomInTool1" runat="server" MapControlID="MapControl1" />
4.定位居中工具
<cc1:CenterTool ID="CenterTool1" runat="server" MapControlID="MapControl1" />
5.移动地图工具
<cc1:PanTool ID="PanTool1" runat="server" MapControlID="MapControl1" />
6.图层工具,显示了和地图相关图层信息,只有当地图缩放到相应的范围里,里面的一些选项才可以操作
<cc1:LayerControl ID="LayerControl1" runat="server" MapControlID="MapControl1" />
6.图例工具,显示了和地图图例相关信息
<cc1:LegendControl ID="LegendControl1" runat="server" MapControlID="MapControl1" />
7.测量工具
<cc1:DistanceTool ID="DistanceTool1" runat="server" MapControlID="MapControl1" />
8.点选择工具,可通过此工具选择一个点
<cc1:PointSelectionTool ID="PointSelectionTool1" runat="server" />
9.矩形选择工具,通过画矩形选择范围内的图层信息
<cc1:RectangleSelectionTool ID="RectangleSelectionTool1" runat="server" />
10.多边型选择工具,通过画多边型工具选择范围内的图层信息
<cc1:PolygonSelectionTool ID="PolygonSelectionTool1" runat="server" />
11.圆圈选择工具,通过画圆圈选择范围内的图层信息
<cc1:RadiusSelectionTool ID="RadiusSelectionTool1" runat="server" />
12.自定义工具,可以自定义事件,命令与返回,即自定义请求与输出,详细待下一节
<cc1:WebTool ID="WebTool1" runat="server" />
使用WebTool工具(七)
本次使用WEbTool自定义工具,实现一个简单的功能
在激发自定义工具后,在地图界面点击时,弹出该点的客户端坐标,与相应的经纬度坐标
一:先从客户端处理怎么发送请求
将工具WebTool 拖到MapForm.aspx界面上,设置对应的地图如下:
<cc1:WebTool ID="WebTool1" runat="server" MapControlID="MapControl1" />
客户端有三个重要的脚本:在项目MapXtremeWebResources文件夹下
1.Interaction.js---交互类型脚本
(已实现的有:ClickInteraction(单击)、RectInteraction(画矩形)..等等,基本是和已有工具对应的)
2.Command.js----命令发送请求脚本
(已实现的有:MapCommand(获取地图)、PanCommand(拖动地图)、DistanceCommand(测量)..等等,基本是和已有工具对应的)
3.Tool.js----------工具命令状态激活脚本
(在激活不同的工具时,改变命令的请求参数)
现在开始处理自定义的客户端脚本请求
1.交互:由于要实现的功能,交互类型也是通过点击引发的,交互就直接使用已有的ClickInteraction
因此设置工具属性:ClientInteraction="ClickInteraction"
2.命令:由于要实现的功能,客户端类型在接收服务端返回的消息后,直接弹出,这点和测量功能是一样的,于是命令就直接使用DistanceCommand
因此设置工具属性:ClientCommand="DistanceCommand"
再设置一个自定义命令文本:Command="GetXY" --这个GetXY是随便起的名字,等一下对应服务端的请求命令
3.交互:自动会处理,啥也不用干
至此,客户端处理完成,实际我们什么也没做,就把工具往界面一拖,然后设置了一下属性:
<cc1:WebTool ID="WebTool1" runat="server" MapControlID="MapControl1" ClientInteraction="ClickInteraction" Command="GetXY" ClientCommand="DistanceCommand" />
二.服务端接收请求并输出信息
在App_Code里,我们新建一个类,叫WebInfoGetXY,让它继承自MapInfo.WebControls.MapBaseCommand
同时加上可序列化属性[Serializable],不加就报错了,配置文件那节里有说到
在构造函数里,写base.Name = "GetXY";//这个就对应了客户端发送的Command
代码如下:
public class WebInfoGetXY:MapInfo.WebControls.MapBaseCommand
{
public WebInfoGetXY()
{
base.Name = "GetXY";
}
}
然后,重写一下Process()方法输出文本即可
代码如下:
public override void Process()
{
MapControlModel model = MapControlModel.GetModelFromSession();
MapInfo.Mapping.Map map = model.GetMapObj(MapAlias);
System.Drawing.Point[] points = ExtractPoints(DataString);
MapInfo.Geometry.DPoint dpoint = new MapInfo.Geometry.DPoint();
map.DisplayTransform.FromDisplay(points[0], out dpoint);//屏幕xy转经纬度
string outText="屏幕xy:" + points[0].X + "," + points[0].Y;
outText+= "<br>经纬度xy:" + dpoint.x +","+ dpoint.y;
HttpContext.Current.Response.Write(outText);
}
服务端到此也就结束了
三.在页面上用代码注册工具命令
if (Session.IsNewSession)
{
MapInfo.WebControls.MapControlModel model = MapInfo.WebControls.MapControlModel.SetDefaultModelInSession();
model.Commands.Add(new WebInfoGetXY());
}