arcgis总结——结合SVG制作轨迹回放

来源:互联网 发布:知堂回想录 pdf 编辑:程序博客网 时间:2024/06/05 17:11

     轨迹回放有几个方案:

     方案一、调用arcgis自己的api,设置定时器,一段时间清空当前点,绘制下一个点。

                     缺点:点的移动不是连续的,一闪一闪的,而且速度不均匀

     方案二、利用HTML5的canvas,原理和上面一样

                      缺点:同上

     方案三、利用SVG制作动画

                      没有缺点,非常完美


      通过比较,最后使用SVG进行制作轨迹回放。

      这里有几个难点:

      1、屏幕坐标和经纬度的同步

      2、SVG动画层会遮盖地图层的事件

      3、由于是连续动画,移动到某时刻并不一定在路径数组的点上,暂停和漫游需要知道回放到的路基数组的具体区间

    

     实现的思路:

     1、启动的时候,动态把SVG的路径解析出来

     2、设置定时器,频率要比播放速度快,尽量快就好了。

           定时器里面做两个事情:a、判断是否到达下一个点,把数组偏移量记录下来。b、判断是否碰到屏幕边界,屏幕边界需要漫游。

           当然,这个定时器只有在播放的时候触发逻辑。

     3、zoomin和zoomout,漫游的时候删除原来SVG动画,通过第二步的数组偏移量,把后续的路径按照新的屏幕坐标解析出来。当前轨迹点也同理重新绘制

     4、屏幕坐标和经纬度的同步可以通过arcgis api里面的方法进行

     5、事件被遮盖的问题,SVG提供了一种方式,通过embed 的wmode="opaque"设置可以解决。但是我这里的SVG如果潜入到embed中,则不方便动态获取DOM,也就不好实现SVG的重绘。因此排除掉此方法。

           考虑到被遮盖的事件只有鼠标点击和滚轮的zoomin和zoomout,鼠标拖动的漫游。而且希望在播放状态的漫游中会自动适配到轨迹,暂停和停止不做限制,因此考虑自己来实现arcgis的以上事件。

     6、鼠标点击和滚轮的zoomin和zoomout的事件通过SVG的鼠标点击事件,事件中直接调用arcgis的api即可。由于SVG没有鼠标拖拽事件,则需要独立实现,把移动的方向获取,然后调用arcgis的api即可。

     下面看一下关键代码

     核心对象:

    

//track用来存储轨迹状态,动态获得播放当前状态var track={      //轨迹的初始经纬度,一旦获得则不能被改变      originalLon:[],      originalLat:[],      //未播放的路径经纬度      lon:[],      lat:[],      //屏幕坐标      x:[],      y:[],      //当前播放点的经纬度      now:[],      //当前播放点的屏幕坐标      nowXY:[],      //轨迹长度      length:0,      //当前数组偏移量      i:0,      //屏幕边界点坐标      limitXY:[],      //设置当前数组偏移量和判断是否碰壁,碰壁则漫游      nowTimer:setInterval(function(){           if(!document)               return;           //设置当前数组偏移量           if(track.lon[track.i]-track.now()<0.0001 && track.lat[track.i]-track.now[1]<0.0001){              if(processManager.isStart)                 track.i++;           //判断是否碰壁,碰壁则漫游           if(track.nowXY[0]>=track.limitXY[0] || track.nowXY[1]>=track.limitXY[1] ||               track.nowXY[0]<=0 || track.nowXY[1]<=0){              if(processManager.isStart){                 var point=new esri.geometry.Point({                     x:track.now[0],                     y:track.now[1]                 });                 map.centerAt(point);              }            }      },50))};//processManager对象用来存储播放状态var processManager={isStart:false};//SVGEvent类用来实现SVG的扩展事件var SVGEvent=function(){  ...}//用静态方法来实现事件绑定SVGEvent.bindEvent=function(element,eventName,fn){   if(!element || element=="svg")       element=window;   //鼠标滚动事件   if(eventName=="mousewheel"){      window.onmousewheel=document.onmousewheel=fn;   }   //鼠标拖动事件   if(eventName=="mouseDrag"){      var state=false,original_x,original_y;      element.onmousedown=function(event){         original_x=e.clientX;         original_y=e.clientY;         state=true;      };      element.onmousemove=function(event){         if(state){            var e=event ? event : window.event;         }      };      element.onmouseup=function(event){         if(state){            state=false;            var diffX=parseInt(event.clientX-original_x);            var diffY=parseInt(event.clientY-original_y);                     var dx="center";            var dy="center";            var d="center";            if(Math.abs(diffX)>80)               dx=diffX>0 ? "right" : "left";            if(Math.abs(diffY)>80)               dy=diffY>0 ? "down" : "up";            if(dx!="center" && dy!="center")               d=dx+dy;            if(dx!="center" && dy=="center")               d=dx;            if(dx=="center" && dy!="center")               d=dy;            fn.call(element,event,dx,dy,d,[event,clientX,event.clientY],[original_x,original_y]);            original_x=0;            original_y=0;            original_left=0;            original_top=0;         }      }   }}

初始化处理的关键代码:

function init(){   //地图的初始化省略   ...   //zoomin、zoomout后重新同步坐标,并且重绘动画   dojo.connect(map,'onZoomEnd',function(){        zoomSVG();   });  //鼠标滚动  SVGEvent.bindEvent("svg","mousewheel",wheel);   //鼠标拖动   SVGEvent.bindEvent("svg","mouseDrag",drag); //初始化边界坐标  track.limitXY=[document.body.clientWidth,docment.body.clientHeight];  //初始化屏幕坐标  initScreenXY();  //初始化svg  initSVG(track);  //加载轨迹线  addTrack(track);}function initScreenXY(){  track.x=[];  track.y=[];  for(var i=0;i<track.length;i++){      var geometry=new esri.geometry.Point(track.originalLon[i],track.originalLat[j]);      var screenPoint=map.toScreen(geometry);      track.x.push(screenPoint.x);      track.y.push(screenPoint.y);  }}function initSVG(track){  //绘制起始点  var circle=document.createElementNS("http://www.w3.org/2000/svg","circle");  circle.setAttribute("id","circle");  circle.setAttribute("cx",track.x[0]);  circle.setAttribute("cy",track.y[0]);  circle.setAttribute("r",8);  document.getElementById("svg").appendChild(circle);  //绘制轨迹  var motionPath=document.createElementNS("http://www.w3.org/2000/svg","path");  motionPath.setAttribute("id","motionPath");  motionPath.setAttribute("fill","none");  var pathParams="M0 0";  for(var i=0;i<track.length;i++){      pathParams="L"+parseInt(track.x[i]-track.x[0])+" "+parseInt(track.y[i]-track.y[0]);  }  motionPath.setAttribute("d",pathParams);  document.getElementById("svg").appendChild(motionPath);}function addTrack(track){   //通过arcgis绘制轨迹线,这样在zoomin,zoomout和漫游后不需要重绘   var path=[];   for(var i=0;i<track.length;i++){       var pos=[];       pos.push(track.lon[i]);       pos.push(track.lat[i]);       path.push(pos);   }   var polyLine=new esri.geometry.Polyline([path]);   var simpleLineSymbol=new esri.symbol.SimpleLineSymbol();   var graphic=new esri.Graphic(polyLine,simpleLineSymbol);   map.graphics.add(graphic);}


动画控制的核心代码如下:

function play(){   if(!processManager.isStart){      document.getElementById("animateMotion").beginElement();      processManager.isStart=true;   }else{      document.getElementById("svg").unpauseAnimations();   }   }}function pause(){   document.getElementById("svg").pauseAnimations();   processManager.isStart=false;}function stop(){   track.i=0;   processManager.isStart=false;   pause();   clearSVG();   initScreenXY();   initSVG(track);}function clearSVG(){   var circle=document.getElementById("circle");   circle.parentNode.removeChild(circle);   var motionPath=document.getElementById("motionPath");   motionPath.parentNode.removeChild(motionPath);}

zoomin,zoomout,漫游后的处理核心代码如下:

function zoomSVG(){   document.getElementById("svg").pausseAnimations();   clearSVG();   reDrawSVG();   if(processManager.isStart)      play();}function panSVG(){   document.getElementById("svg").pausseAnimations();   clearSVG();   reDrawSVG();   if(processManager.isStart)      play();<span style="font-family: Arial, Helvetica, sans-serif;">}function reDrawSVG(){   //初始化剩余路线的坐标信息   var lon=[];   var lat=[];   var x=[];   var y=[];   //是否播放到最后一段,最后一段特殊处理  if(track.i<track.length){     for(var i=track.i;i<track.length;i++){     if(!track.originalLon[i])        break;        lon.push(track.originalLon[i]);        lat.push(track.originalLat[i]);        var geometry=new esri.geometry.Point(track.originalLon[i],track.originalLat[i]);        var screenPoint=map.toScreen(geometry);        x.push(screenPoint.x);        y.push(screenPoint.y);     }  }   else{     lon.push(track.originalLon[track.i-1]);     lat.push(track.originalLat[track.i-1]);     var geometry=new esri.geometry.Point(track.originalLon[track.i-1],track.originalLat(track.i-1));     var screenPoint=map.toScreen(geometry);     x.push(screenPoint.x);     y.push(screenPoint.y);  }  //绘制当前点  var circle=document.createElementNS("http://www.w3.org/2000/svg","circle");  circle.setAttribute("id","circle");  circle.setAttribute("cx",x[0]);  circle.setAttribute("cy",y[0]);  circle.setAttribute("r",8);  document.getElementBuId("svg").appendChild(circle);   //绘制SVG轨迹   var motionPath=document.createElementNS("http://www.w3.org/2000/svg","path");   motionPath.setAttribute("id","motionPath");  motionPath.setAttribute("fill",none);  var pathParams="M0 0";  //是否播放到最后一段,最后一段特殊处理  if(track.i<track.length){      for(var i=0;i<x.length;i++){          pathParams+="L"+parseInt(x[i]-x[0])+" "+parseInt(y[i]-y[0]);       }   }   else{      pathParams+="L"+parseInt(x[x.length-1]-x[0])+" "+parseInt(y[y.length-1]-y[0]);   }   motionPath.setAttribute("d",pathParams);   document.getElementById("svg").appendChild(motionPath);}

获得当前点的经纬度,屏幕坐标核心代码如下:

function now(){   var circle=document.getElementById("circle");    if(circle){      //当前的屏幕坐标      var ctm=circle.getCTM();      var x=circle.getAttribute("cx");      var y=circle.getAttribute("cy");      track.nowXY[0]=x*ctm.a+y*ctm.c+ctm.e;      track.nowXY[1]=x*ctm.b+y*ctm.d+ctm.f;      //当前的经纬度坐标      var screenPoint=new esri.geometry.ScreenPoint({          x:track.nowXY[0],          y:track.nowXY[1]      });      var point=map.toMap(screenPoint);      track.now[0]=point.x;      track.now[1]=point.y;   }}

实现鼠标点击,滚轮的zoomin,zoomout和鼠标拖动漫游的核心代码如下:

//事件的绑定在init中,这里是绑定的functionfunction wheel(evt){   if(evt.deltaY>0){      zoomIn();   }   else{      zoomOut();   }}function zoomIn(){   var extent=map.extent;   map.setExtent(extent.expand(0.5));}function zoomOut(){   var extent=map.extent;   map.setExtent(extent.expand(2));}function drag(event,dx,dy,d,point,originalPoint){   if(d=="right")      map.panLeft();   if(d=="left")      map.panRight();   if(d=="up")      map.panDown();   if(d=="down")      map.panUp();   if(d=="leftup")      map.panLowerRight();   if(d=="leftdown")      map.panUpperRight();   if(d=="rightup")      map.panLowerLeft();   if(d=="rightdown")      map.panUpperLeft();<span style="background-color: rgb(240, 240, 240);">}




     

0 0
原创粉丝点击