阅读:30979回复:67
[原创]另辟渠道的webgis应用开发(附源码)
<P> 在用ARCIMS开发webgis中小型应用程序的时候,我相信很多人和我一样,就是如何将保存在简单数据库(如ACCESS)里的一些专题点信息该如何体现在地图上,这些点多则有3000,4000,另外还可通过地图操作(添加,平移)进行专题点编辑。如果直接用HTML VIEWER,这可是个不大不小的难题。一开始,我们使用了ACETATELAYER方式进行处理,效果不甚理想,在局域网中多用户并发访问时就有明显的速度瓶颈,更何况INTERNET上。
如下代码就是在此问题上做出的一种解决方案尝试,即部分地图信息客户端化。目前我正在开发,只是部分调试仅在局域网中通过,并没有完全成熟,在线面上还是处理开发阶段。现在介绍一下代码的基本思想,希望大家能够加以讨论。该代码使用JAVASCRIPT开发,它已基础图层地图图片为底图,在此之上进行图层扩展,客户端形成一套小型的webgis,与ARCIMS同步刷新,形成无缝整合,给人感觉就是一个整体的webgis系统。该代码在对象层次关系上模拟ACTIVEX CONNECTOR的重点对象。通过不同refresh函数与基础图层同步更新(为提高客户端速度,开放了很多refresh方式,即只refresh发生改变的对象坐标位置,当然放大缩小平移之类的操作就需要整个客户端refresh,因为每个点都发生了位置变化)。之所以如此层次化,一方面是为了增强代码的可读性和可维护性,另一方面通过封装具体VML代码实现来简化开发过程。这样一来,可以大大减轻服务端的处理,客户端和服务端同时处理,提高地图的运行速度。 我想重点说明的是,如果将部分地图信息移到客户端,必然需要自主开发一些原本集成好的功能(比如说在FeatureLayer中的WHEREEXPRESSION,BUFFER等功能)用于客户端。以BUFFER为例,圆形如何画,必然是vml的 oval,可以把它作为一个特殊地图图层来看待,它是一个圆,而不是点,线,区(折线),这就是图层类型扩展。同样的道理还用在监控(关于监控的需求可查看<a href="http://www.gisempire.com/bbs/dispbbs.asp?BoardID=23;ID=14998" target="_blank" >http://www.gisempire.com/bbs/dispbbs.asp?BoardID=23;ID=14998</A>),它是一种特殊的点层,它具体表现内容更丰富,所以也可以把它看成一种图层类型。 当然,之所以费尽心思放在客户端做,还有个很重要的目的就是为了解决地图特殊信息的可编辑。首先说明,此方法对基础图层的属性是无能为力的,它仅是用于在客户端生成的专题信息。 以本代码为例,客户端添加一个新点则需要先在相关对象中add,还需要通过数据库的方式将点保存。如果移动某客户端生成点,则显示客户端的移动过程,然后更改该对象的left和top到XY即可。另外要注意的是,客户端gismap对象中的所有涉及点的坐标都是地图坐标,所以经常需要屏幕坐标和地图坐标之间的转换,以前我说过,现在就不多说了,代码也体现比较明显。 以下是未完成代码的详细内容,以后会将很多实现补充上来,希望给有此需求的人员带来启示,并欢迎大家跟贴讨论,恭请候教。 function GisMap() { var i ; this.control = drawonmap ; //控件名称 this.visible = true ; //是否显示 this.mapXMin = 0 ; //地图最小X this.mapYMin = 0 ; //地图最小Y this.mapXMax = 0 ; //地图最大X this.mapYMax = 0 ; //地图最大Y this.layers = new Layers() ; //图层集合对象</P> <P>///返回含屏幕坐标的point对象 this.fromMapPoint=function(mapX,mapY) { var point = new PointObject() ; point.x = getJX(mapX) ; point.y = getWY(mapY) ; return point ; }; ///返回含地图坐标的point对象 this.toMapPoint=function(screenX,screenY) { var point = new PointObject() ; point.x = getScrX(screenX) ; point.y = getScrY(screenY) ; return point ; }; //获得地图坐标 function getJX(scrX) { return (this.mapXMin+parseInt(scrX)/(document.body.clientWidth/(this.mapXMax - this.mapXMin))); } function getWY(scrY) { return (this.mapYMax-parseInt(scrY)/(document.body.clientHeight/(this.mapYMax-this.mapYMin))); } //获得屏幕坐标 function getScrX(mapX) { return (mapX - this.mapXMin) * document.body.clientWidth/(this.mapXMax-this.mapXMin) ; } function getScrY(mapY) { return (this.mapYMax - mapY) * document.body.clientHeight/(this.mapYMax-this.mapYMin) ; }</P> <P> ///画图 ///在不同环境下可更改此函数的实现 this.draw=function() { for (i=1;i<this.layers.count+1;i++) { this.drawLayer(this.layers.item(i)) ; //this.control.innerHTML = this.stringBuilder.toString() ; } };</P> <P> ///绘制指定层 this.drawLayer=function(layerObject) { switch (layerObject.type) { case "tail" : drawTailLayer(layerObject) ; break; case "denamic" : drawDynamicLayer(this.control,layerObject) ; break; case "point" : drawPointLayer(this.control,layerObject) ; break; case "line" : break; case "polygon" : break; } };</P> <P> //绘制监控层 function drawTailLayer(layerObject) { var sHTML ; var tailObject = eval("div_tail") ; var arr0 ; for (i=1;i<layerObject.count+1;i++) { sHTML = '<div id="' + layerObject.item(i).id + '" name="' + layerObject.item(i).name + '"' ; sHTML+= ' style="position:absolute;z-index:3;left:' + getScrX(layerObject.item(i).x) + ';top:' + getScrY(layerObject.item(i).y) + '">'; arr0 = layerObject.item(i).content.split(",") ; if (arr0.length>0) { sHTML+= '<table border=0 width=108 bgcolor=#1949A1 cellspacing=1 cellpadding=0 style="font-size:9pt">' ; sHTML+= '<tr><td>' ; sHTML+= '<table border=0 width="100%" cellspacing=0 cellpadding=0>' ; sHTML+= '<tr><td><img src="images/tail/tailtable_top.gif"></td></tr>' ; sHTML+= '<tr><td background="images/tail/tailtable_bg.gif">' ; sHTML+= '<table border=0 width="100%" cellspacing=0 cellpadding=3>' ; for (j=0;j<arr0.length;j++) { sHTML+= '<tr><td height="20" style="color:white;font-size:9pt">' + arr0[j] + '</td></tr>' ; } sHTML+= '</table>' ; sHTML+= '</td></tr></table>' ; sHTML+= '</td></tr></table>' ; } sHTML+= '</div>' ; tailObject.innerHTML+= sHTML ; } } //绘制点层 function drawPointLayer(parentObject,layerObject) { var i ; var oSB = new StringBuilder() ; if (layerObject.symbol!=null) { for (i=1;i<=layerObject.count;i++) { //oSB.append(setPointVML(layerObject.item(i),layerObject.symbol)) ; setPointVML(parentObject,layerObject.item(i),layerObject.symbol) ; } } else { for (i=1;i<=layerObject.count;i++) { //oSB.append(setPointVML (layerObject.item(i))) ; setPointVML (layerObject.item(i)) ; } } return oSB ; } //绘制线层 function drawLineLayer(layerObject) { for (i=0;i<layerObject.count;i++) { if (layerObject.symbol!=null) { } else { } } } //绘制区层 function drawPolygonLayer(layerObject) { var sHTML ; for (i=0;i<layerObject.count;i++) { if (layerObject.symbol!=null) { } else { } } } //绘制动态图层 function drawDynamicLayer(layerObject) { var sHTML ; sHTML = "" ; for (i=0;i<layerObject.count;i++) { if (layerObject.item(i).type == "point") { } else if (layerObject.item(i).type == "line") { } else if (layerObject.item(i).type == "polygon") { } } }</P> <P> ///客户端绘图更新 ///在此处,更新的含义更多体现为更改各要素在屏幕的坐标,即left和top this.refresh=function() { var obj ; var i,j ; for (i=1;i<this.layers.count+1;i++) { switch (this.layers.item(i).type) { case "tail": for (j=1;j<this.layers.item(i).count+1;j++) { //alert(i + "," + j) ; obj = eval(this.layers.item(i).item(j).id) ; obj.style.left = getScrX(this.layers.item(i).item(j).x) ; //alert(i+";" + j + ":" + this.layers.item(i).item(j).x + "," + obj.style.left) ; obj.style.top = getScrY(this.layers.item(i).item(j).y) ; //alert(i+";" + j + ":" + this.layers.item(i).item(j).y + "," + obj.style.top) ; } break; case "point": for (j=1;i<this.layers.item(i).count+1;j++) { obj = eval(this.layers.item(i).item(j).id) ; obj.style.left = getScrX(this.layers.item(i).item(j).x) ; alert(obj.style.left) ; obj.style.top = getScrY(this.layers.item(i).item(j).y) ; } break; case "" : } } } //画点对象 function setPointVML(parentObject,pointObject,symbolObject) { var sHTML = "" ; switch (symbolObject.style) { //圆形 case 0 : sHTML+='<v:oval' ; if (pointObject.id!="") sHTML+= " id=\"" + pointObject.id + "\""; if (pointObject.name!="") sHTML+= " name=\"" + pointObject.name + "\""; sHTML+= ' style="position:relative;' ; if (symbolObject.size>0) { if (pointObject.y!="") sHTML+= 'top:' + (parseInt(pointObject.y)+symbolObject.size/2) + ';' ; if (pointObject.x!="") sHTML+= ' left:' + (parseInt(pointObject.x)+symbolObject.size/2) + ';' ; sHTML+= 'width:' + symbolObject.size + ';' ; sHTML+= 'height:' + symbolObject.size + ';' ; } if (symbolObject.color!="") sHTML+= ' fillcolor="' + symbolObject.color + '"'; if (symbolObject.border>0) { sHTML+= ' strokeWeight="' + symbolObject.border + '"' ; if (symbolObject.bordercolor>0) sHTML+= ' strokeColor="' + symbolObject.bordercolor + '"' ; } sHTML+="></v:oval>" ; break; //矩形 case 1 : sHTML+='<v:rect ' ; if (pointObject.id!="") sHTML+= " id=\"" + pointObject.id + "\""; if (pointObject.name!="") sHTML+= " id=\"" + pointObject.name + "\""; sHTML+= ' style="position:relative;' ; if (symbolObject.size>0) { if (pointObject.y!="") { sHTML+= 'top:' + String(parseInt(pointObject.y)+symbolObject.size/2) + ';' ; } if (pointObject.x!="") sHTML+= ' left:' + (parseInt(pointObject.x)+parseInt(symbolObject.size/2)) + ';' ; sHTML+= 'width:' + symbolObject.size + ';' ; sHTML+= 'height:' + symbolObject.size + ';' ; } if (pointObject.color!="") sHTML+= ' fillcolor="' + symbolObject.color + '"'; if (pointObject.border>0) { sHTML+= ' strokeWeight="' + symbolObject.border + '"' ; if (symbolObject.bordercolor>0) sHTML+= ' strokeColor="' + symbolObject.bordercolor + '"' ; } sHTML+="></v:rect>" ; break; //图片 case 10 : sHTML+='<v:image ' ; if (pointObject.id!="") sHTML+= " id=\"" + pointObject.id + "\"" ; if (pointObject.name!="") sHTML+= " id=\"" + pointObject.name + "\"" ; if (symbolObject.image!="") { sHTML+= ' src="' + symbolObject.image + '"' ; sHTML+=' style="top:' + pointObject.y + ';left:' + pointObject.x + '"' ; } sHTML+= "></v:image>" ; break; } var newPoint = document.createElement(sHTML) ; parentObject.insertBefore(newPoint) ; } }</P> <P>///layers集合 function Layers() { var pri_LayerArray = new Array() ; this.count=pri_LayerArray.length ; this.item=function(index) { return pri_LayerArray[index-1] ; }; this.add=function(layer) { pri_LayerArray[pri_LayerArray.length] = layer ; this.count=pri_LayerArray.length ; }; this.remove=function(index) { var i ; for (i=index;i<pri_LayerArray.length;i++) { pri_LayerArray[index-1] = pri_LayerArray[index] ; } pri_LayerArray[pri_LayerArray.length-1] = null ; this.count=pri_LayerArray.length ; } }</P> <P>///自我约束的layer模式,点线面图层需谨慎使用 ///使用错误则不能自我判别 function LayerObject(layerid,layername) { var pri_objArray =new Array(); this.id = layerid ; this.name = layername ; this.visible = true ; this.type = "dynamic" ; this.symbol = null ; this.count = pri_objArray.length ; this.add=function(object) { pri_objArray[pri_objArray.length] = object ; this.count = pri_objArray.length ; } ; this.item = function(index) { return pri_objArray[index-1] ; } this.remove=function(index) { for (i=index;i<this.count;i++) { pri_objArray[index-1] = pri_objArray[index] ; } pri_objArray[pri_objArray.length-1] = null ; this.count = pri_objArray.length ; } this.setSymbol=function(object) { if (this.type == "dynamic") { return null ; } else { this.symbol = object ; //symbol赋值 } } }</P> <P>//PolyLine对象 function PolyLineObject() { var pri_PolyLine = null; var pri_Stroke = null ; this.parent = null ; this.id = "" ; this.Points = new Points() ; this.filled = "false" ; this.startArrow = "" ; this.endArrow = "" ; this.dashStyle = "" ; } //点集合 function Points() { var pri_Points = new Array() ; this.count = pri_Points.length ; this.item=function(index) { return p_Points[index-1] ; }; this.add=function(pointObject) { p_Points[p_Points.length] = pointObject ; this.count = getLength() ; }; this.remove=function(index) { var i ; for (i=index;i<this.count;i++) { pri_Points[index-1] = pri_Points[index] } pri_Points[pri_Points.length-1] = null ; this.count = getLength() ; } function getLength() { return p_Points.length ; } }</P> <P>//线对象 function LineObject() { var line = null ; this.parent = null ; this.id = "" ; this.fromX = 0 ; this.fromY = 0 ; this.toX = 0 ; this.toY = 0 ; this.symbol = new LineSymbol() ; }</P> <P>//点对象 function PointObject(id,name,code,x,y) { this.id = id ; this.name = name ; this.code = code ; this.x = x ; this.y = y ; this.symbol = null ; }</P> <P>//监控对象 function TailObject() { this.id = "" ; this.id = "" ; this.x = "" ; this.y = "" ; this.content = "" ; }</P> <P>///范围 function Envelope(xmin,ymin,xmax,ymax) { this.xMin = xmin ; this.yMin = ymin ; this.xMax = xmax ; this.yMax = ymax ; }</P> <P>function PointSymbol() { this.style=0 ; this.size=10 ; this.border=0 ; this.color = "red" ; this.bordercolor="" ; this.transparency = 1 ; this.image="" ; //如果style=image,给这个属性赋值(相对路径) }</P> <P>//字符串连接操作类,大量字符串累加的时候可提高效率 function StringBuilder(sString) {</P> <P> this.length=0; this._current=0; this._parts=[]; this._string=null; if(sString!=null) this.append(sString);</P> <P> this.append=function(sString) { this.length+=(this._parts[this._current++]=String(sString)).length; this._string=null; return this; } this.appendSB = function(stringBuilder) { //for (i=0;i<stringBuilder.length;i++) //{ // this.append(String(stringBuilder._parts)) ; //} this.append(stringBuilder.toString()) ; return this ; } this.toString=function() { if(this._string!=null) return this._string; var s=this._parts.join(""); this._parts=[s]; this._current=1; return this._string=s; } } </P> |
|
1楼#
发布于:2004-09-27 19:43
<P>经典!</P><img src="images/post/smile/dvbbs/em05.gif" /><img src="images/post/smile/dvbbs/em02.gif" /><img src="images/post/smile/dvbbs/em01.gif" />
|
|
2楼#
发布于:2004-09-27 20:31
<P>经典,加精,置顶,奖励!</P>
<P><img src="images/post/smile/dvbbs/em02.gif" /><img src="images/post/smile/dvbbs/em02.gif" /></P> <P>最主要的是这种共享的精神,探索的精神!!</P> [此贴子已经被作者于2004-9-27 20:32:35编辑过]
|
|
|
3楼#
发布于:2004-09-29 08:51
<img src="images/post/smile/dvbbs/em01.gif" /><img src="images/post/smile/dvbbs/em06.gif" /><img src="images/post/smile/dvbbs/em06.gif" /><img src="images/post/smile/dvbbs/em05.gif" />
|
|
4楼#
发布于:2004-10-05 19:52
<img src="images/post/smile/dvbbs/em01.gif" /><img src="images/post/smile/dvbbs/em01.gif" /><img src="images/post/smile/dvbbs/em01.gif" /><img src="images/post/smile/dvbbs/em02.gif" />
|
|
5楼#
发布于:2004-10-11 17:19
<P>居然置顶啦,哈哈,谢谢斑竹的鼓励和支持。最近外出旅游了一番,开发停了下来,未来一段时间,将全面再开发,届时再传递最新的代码。另外需要说明的是,该代码无法独立运行,需结合客户端以及服务端的一些操作来协调运行,所以公布此代码的目的只是为了更多的是描述这种开发思想,开发人员可在此基础上自行扩展和完善。另外,对我个人来说,公开源码本来也没什么,只是基于商业方面的原因,我不能公开全部源码,但可就设计和开发过程的问题进行交流。我的QQ:24637884</P>
[此贴子已经被作者于2004-10-12 9:00:35编辑过]
|
|
6楼#
发布于:2004-10-11 20:59
<img src="images/post/smile/dvbbs/em05.gif" />
|
|
7楼#
发布于:2004-10-15 08:31
<P>继续支持,</P><img src="images/post/smile/dvbbs/em02.gif" /><img src="images/post/smile/dvbbs/em02.gif" />
|
|
|
8楼#
发布于:2004-10-18 11:16
<P>不错,是一种不错的方法</P><P>其实,这种思路在go2map上也有应用,不过是面向公众的服务,没有做很多深入的功能(例如编辑),只是将高亮某一个物体的时候,在客户端做了这些工作,下面叠加了栅格图片</P>
|
|
9楼#
发布于:2004-11-04 11:50
<img src="images/post/smile/dvbbs/em01.gif" /><img src="images/post/smile/dvbbs/em03.gif" /><img src="images/post/smile/dvbbs/em02.gif" />
|
|
|
上一页
下一页