svg+JS 实现 的一个小GIS

时间:2022-11-20 18:36:44

想起来自己也是学习地理信息系统专业的学生,于是想着还是要做点和地理信息系统有关系的事情才对.

于是想用svg来实现一个小的地理信息系统.

想来应该是很酷的东西~

老师给我介绍了了一个叫做Raphael的开源库.利用这个可以做出很多svg的漂亮效果,并且添加事件也会很容易。(谢!)

Raphael的网址是:http://raphaeljs.com

大家可以看一下,上面有很多的例子.并且文档也很详细.

有一个中文的在线文档,地址是http://julying.com/lab/raphael-js/docs/

好了。下面来说如何实现:

首先.一个GIS系统,需要地理底图,这里因为找不到合适的矢量图,我从网上找了一个栅格图,然后用inkscape简单的矢量化了一下.将就用吧~

svg+JS 实现 的一个小GIS

 

好了咱们给它命名为mapHB.svg。

然后我们要把这个图导入成为底图:

(ps:因为最近使用的是thinkphp的框架做东西,所以这里也是使用的thinkphp框架来做的~)

在php这边,我们要把svg的信息读出:

1      $fileName="./Public/Svg/mapHB.svg";
2 $content=file_get_contents($fileName);
3 //读出svg文件内容4 //替换掉svg文本中的换行。避免SVGimport出错。
5 $content=preg_replace( "([\r\n])","", $content);
6 $this->assign("content",$content);

读出后assign在content上。然后在模板这边画上,首先,我们要引入一些库。

1 <script type="text/javascript" src="__PUBLIC__/Js/raphael.2.1.0.min.js"></script><!--Raphael-->
2 <script type="text/javascript" src="__PUBLIC__/Js/raphael-svg-import.js"></script><!--svg导入-->
3
4 <script type="text/javascript" src="__PUBLIC__/Js/jquery.js"></script>
5 <script type="text/javascript" src="__PUBLIC__/Js/jquery.mousewheel.min.js"></script><!--这个是滚轮事件的jquery库-->

第一个是raphael的库,第二个是svg导入的库。最后一个是鼠标滚轮事件的库。

好,现在要导入svg图:

var box=document.getElementById('paper');
//这里是滚轮事件。这里paper是一个全局变量
//
paper的_viewBox属性原本是没有的,但是在设置setViewBox后就有了。所以要先对paper使用setViewBox
//
当然缩放过程必须按照比例来。
$('#paper').mousewheel(function(event, delta, deltaX, deltaY) {
if(delta>0){
var sX=paper._viewBox[0];
var sY=paper._viewBox[1];
var sW=paper._viewBox[2];
var sH=paper._viewBox[3];
var bili=sH/sW;
var H=70*bili;
if(sW-70>0&&sH-H>0){
paper.setViewBox(sX
+35,sY+H/2,sW-70,sH-H);
}
}
else{
var sX=paper._viewBox[0];
var sY=paper._viewBox[1];
var sW=paper._viewBox[2];
var sH=paper._viewBox[3];
var bili=sH/sW;
var H=70*bili;
paper.setViewBox(sX
-35,sY-H/2,sW+70,sH+H);
}
});
//这里是设置画布的大小 需要调整一下。
paper = Raphael("paper",box.clientWidth-20,window.innerHeight-45);

//这里就是导入svg图像。
var newSet = paper.importSVG('{$content}');

导入成功后,我们要给地图做拖动事件,也就是gis里的漫游,基本思想是:因为在原有的导入的svg上拖动的话,由于填充问题,有的地方不能响应raphael的drag事件,所以我们可以新建一个极大的rect,来覆盖整个地图,以及周围区域。并用透明色填充。这样可以看见底图,并且可以响应拖动。

 

当然我们要做3个功能,漫游,拖框放大,滚轮缩放。区分这三个功能的方法,我是用的鼠标样式,首先点击功能按钮,改变鼠标样式,然后在和地图交互的过程中,判断鼠标的样式,就可以知道是什么功能。

改变样式的实现如下:

         $('#move').click(function(){
document.getElementById(
'paper').style.cursor="move";
}).mouseover(function(){
$(
'#move').animate({
width:
30
});
}).mouseout(
function(){
$(
'#move').animate({
width:
24
});
});

$(
'#zoomAll').click(function(){
paper.setViewBox(
0,0,box.clientWidth,box.clientHeight,true);
}).mouseover(
function(){
$(
'#zoomAll').animate({
width:
30
});
}).mouseout(
function(){
$(
'#zoomAll').animate({
width:
24
});
});

$(
'#zoom').click(function(){
document.getElementById(
'paper').style.cursor="nw-resize";
}).mouseover(
function(){
$(
'#zoom').animate({
width:
30
});
}).mouseout(
function(){
$(
'#zoom').animate({
width:
24
});
});

然后,我们就可以根据样式来做各种功能了。

我们先来看看drag事件的用法:

Element.drag(onmove, onstart, onend, [mcontext], [scontext], [econtext])

前3个函数是必须的,一个是在鼠标拖动过程中的事件,一个是开始拖动的事件,一个是结束拖动的事件。

onmove有5个参数(dx,dy,x,y,event);

分别是x移动距离,y移动距离,鼠标位置x,y。

onstart有3个参数(x,y,event);

就是鼠标的x,y

onend只有一个(event)

首先是move(漫游):

直接在onmove事件添加这个function就可以实现:

if(action=="move"){
x0
=paper._viewBox[0]-dx/30;
y0=paper._viewBox[1]-dy/30;
W=paper._viewBox[2];
H
=paper._viewBox[3];
paper.setViewBox(x0,y0,W,H,
true);
}

然后是拖框放大:

基本思想是,拖框,画出一个矩形,然后根据矩形的宽度来按照比例调整viewBox大小,这样就可以实现缩放。

首先开始拖动的时候,记录下来开始拖动的点。但是要把鼠标的clientx,y转换成画布的位置坐标:

              if(action=="nw-resize"){
//获取画布上的坐标
var box=document.getElementById('paper');

var scrollX;
var scrollY;
if(window.scrollX||window.scrollY){
scrollX
=window.scrollX;
scrollY
=window.scrollY;
}
else{
scrollX
=document.documentElement.scrollLeft;
scrollY
=document.documentElement.scrollTop;
}
var bx=$('#paper').offset().left-scrollX;
var by=$('#paper').offset().top-scrollY;
//var bx=0;
//var by=0;
var zoombiliW=originalScaleW/paper._viewBox[2];
var zoombiliH=originalScaleH/paper._viewBox[3].toFixed(0);
var mx=((event.clientX-bx)/zoombiliW+paper._viewBox[0]);
var my=((event.clientY-by)/zoombiliH+paper._viewBox[1]);
DstartX=mx;
DstartY
=my;
  }

然后在onmove中就要画rect了:

            if(action=="nw-resize"){
var zoombiliW=originalScaleW/paper._viewBox[2];
var zoombiliH=originalScaleH/paper._viewBox[3].toFixed(0);
              //存在area的话先remove,这样才能有拖框的效果
if(area){
area.remove();
area
=paper.rect(DstartX,DstartY,dx/zoombiliW,dy/zoombiliH);
}
else{
area
=paper.rect(DstartX,DstartY,dx/zoombiliW,dy/zoombiliH);
}

}

最后在onend里,就要根据rect来放大了:

            if(action=="nw-resize"){

var x=area.attrs.x;
var y=area.attrs.y;
var width=area.attrs.width;
var sW=paper._viewBox[2];
var sH=paper._viewBox[3];
var bili=sH/sW;
var height=width*bili;
paper.setViewBox(x,y,width,height);
              
//最后还是把框remove掉咯。
area.remove();

}

好了,到这里,三个功能就都实现了(漫游,滚轮缩放,拖框放大)。地图操作的基本功能有了。以后还准备做一点打点,加入地理信息的功能。等做好了再弄上来。