svg webtopo原型8 -拖曳

本文介绍了在SVG WebTopo中实现设备拖曳功能的挑战及解决方案,强调了坐标变换的重要性。在兼容性方面,特别是对于IE的embed需要设置wmode属性,同时针对IE和Opera对clientX的不同处理,采用不同的算法来计算鼠标点击位置。文章提到了相关的封装操作,如topo.js和movobjs.js,并提及了一个简洁的算法参考。

这回是真正的考验了,要实现设备的鼠标拖曳功能。

这个功能理论上比较简单,但是为了兼容性,几乎吐血。

实现的方法有很多,这里仅列举一种。

核心就在于坐标变换,主要有三点注意

针对ieembed,需要注意设置wmode="Transparent"属性,这样可以不影响页面的鼠标事件。

再有就是IE/asv不支持offsetX方法,所以需要自行设法计算鼠标点击位置相对设备的坐标。

Ieoperaclientx的取值不同ie是相对svg元素的坐标,opera是相对整个页面的坐标,因此移动函数采用了不同的算法。

6dev.htm

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>
设备
</title>
 <meta http-equiv="X-UA-Compatible" content="chrome=1">
<!-- legengd.html
 1.显示设备(文字、图片)
 2.拖动
-->
</head>
<script type="text/javascript" language="javascript" src="./js/moveObjs.js"></script>
<script type="text/javascript" language="javascript" src="./js/svgutil.js"></script>
<script type="text/javascript" language="javascript" src="./js/topo.js"></script>

<script>

</script>

<body bgcolor="#ffffff">


<br>
<button onclick="show()">开始</button><br>
<button onclick="zoomby(0.5)">缩小2倍cor</button>
<button onclick="zoomby(2)">放大 2倍cor</button>
<button onclick="zoom(1,300,300)">还原</button><br>
<button onclick="showsrc()">源码</button><br>
<button onclick="movetest()">移动</button><br>
<div id="divsvg" style="position: absolute;top:180;left:0"></div>
<div id="pos"></div>
<div id="pos1"></div>
</body>
<script>


var svg;
var svgw=400;
var svgh=300;
//var svgdoc;
var plat;

function show(){
 
 svg=initSVG(svgw,svgh);
 //延迟一下,最小是10ms
 var tidst=window.setTimeout(show1,20);
}

function show1(){
 //var svg;
 //svg=initSVG(200,200);
 //var svgdoc;
 svgdoc=getSVGDocument(svg);
 plat=getrootg(svg,svgdoc);
 

 //生成一个设备
 curentStyle="stroke:black;fill:green";
 var device=createDev("DEV00005",100,100,29.0,17.0,"./image/DEV_IP_R.gif","XM-BB-GSR12816-D-1.MAN(61.154.237.12)");
 }
 
 function movetest(){
 //验证一下svg的group能否整体移动
  var svgdoc=getSVGDocument(svg);
  var plat=svgdoc.getElementById('DEV00005');
  
  plat.setAttribute("transform","translate(0,50)");
		
}

</script>
</html>

相关的操作进行了一下封装

设备相关的。topo.js


 

//3.二级函数
//这里的位置和大小是由摆放算法确定的

//节点。别名,叫设备有点太具体
function createNode(id,x,y,width,height,imageSrc,name,target,style){
	var node=createDev(id,x,y,width,height,imageSrc,name,target,style);
	return node;
}	

function createDev(id,left,top,width,height,imageSrc,name,target,style){
	
	//设备首先包含一个group
	style="fill:red";
  var group=createGroup(id,left,top,width,height ,name,style);
  //group.setAttribute("hasAlarm",false);
  //if (target == undefined){
  if (!target){
  	var svgdoc1=getSVGDocument(svg);
  	var plat1=getrootg(svg,svgdoc1);
    plat1.appendChild(group);
  }
  else{
    target.appendChild(group);
  }

  
  //在svg中,元素位置都是相对svg的。文本显示在起点的右上,矩形和图片显示在右下
  //设备的图片
  var image=createImage(top,left,width,height,imageSrc);
  
  group.appendChild(image);

  //设备的名称
  style="fill:blue;cursor:move";
  var namebox=createText(top,left,name,style); 
  group.appendChild(namebox);
  
  //相对坐标移动
  //移动的相关事件
  if(isIE){

  	group.setAttribute("onmousedown","dragie(evt,this)");
     }
  else{
  	group.setAttribute("onmousedown","drago(evt,this)");
  }
  
  
  //可选,用于绝对坐标移动
    group.movetopos=function(ckx,cky){
  	
  	group.setAttribute("x",ckx);
  	group.setAttribute("y",cky);
  	image.setAttribute("x",ckx);
  	image.setAttribute("y",cky);
  	namebox.setAttribute("x",ckx);
  	namebox.setAttribute("y",cky);
  }
  return group;
}

//创建电路
//连线的位置需要根据设备的起点和大小进行计算,top对应y,left对应x.top+weight/2

function createCircuit(id,x1,y1,x2,y2,name,title,id1,id2,target,style){
	var line=createLink(id,x1,y1,x2,y2,name,title,target,style);
	//起点
	var svgdoc1=getSVGDocument(svg);

	var fromObj=svgdoc1.getElementById(id1);

  //var fromLinks=fromObj.getAttribute("fromLinks");
  var fromLinks=fromObj.fromLinks;
  if(fromLinks==null){
    fromLinks=new Array();
    
  }
  //追加到数组末尾,便于拖动时计算
  //alert(fromLinks.length);
  fromLinks[fromLinks.length]=line;
  //fromObj.setAttribute("fromLinks",fromLinks);
  fromObj.fromLinks=fromLinks;
  //alert(fromLinks.length);
  //var fromLink=fromObj.fromLinks;;
  //alert(fromLink[0].id);
	//终点
	 var toObj=svgdoc1.getElementById(id2);
  var tolinks=toObj.toLinks;
  if(tolinks==null){
    tolinks=new Array();
    toObj.setAttribute("toLinks",tolinks);
  }
   //追加到数组末尾,便于拖动时计算
  tolinks[tolinks.length]=line;
  toObj.toLinks=tolinks;
  
    //位置和大小。
  line.setAttribute("hasAlarm",false);
  
	
	return line;
}

//创建线型
function createStroke(line){
	var curstyle=line.getAttribute("oristyle");
	var newstyle=";stroke-dasharray: 9, 5";
	var style=curstyle+newstyle;
	//alert(style);
	line.setAttribute("style",style);
}
//删除线型
function removeStroke(line){
  var curstyle=line.getAttribute("oristyle");
  //alert(curstyle);
  line.setAttribute("style",curstyle);
}


 移动相关的movobjs.js

这个算法参照了网上的一个经典方法,非常简洁。

 

var xx=0,yy=0;
var moveobj=null,ckleft=0,cktop=0,ckw=0,ckhei=0,ckto="";
var tempx,tempy;
var showDevRelaCir=true;
var fromLinks=null;
var toLinks=null;
var moving;

function dealLineWhenChoose(moveobj){
		//处理设备相关的电路信息
		
	//点中设备的相关电路变虚线
	if(showDevRelaCir==true){
		
		//清除前次的线型
	  if(fromLinks!=null)
	    for(var i=0;i<fromLinks.length;i++){
	      removeStroke(fromLinks[i]);
	    }
	  if(toLinks!=null)
	    for(var i=0;i<toLinks.length;i++){
	      removeStroke(toLinks[i]);
	    }
	    //重画线型
	   fromLinks=moveobj.fromLinks;
	  // alert(fromLinks.length);
	   if(fromLinks!=null)
	    for(var i=0;i<fromLinks.length;i++){
	      createStroke(fromLinks[i]);
	    }
	   toLinks=moveobj.toLinks;
	    if(toLinks!=null)
	      for(var i=0;i<toLinks.length;i++){
	        createStroke(toLinks[i]);
	      }
	    }
}

//js移动设备
function movdev(moveobj,ckx,cky){

    
    if(moveobj!=null){			
    	  moveobj.setAttribute("transform","translate("+ckx+","+cky+")");
     
     //移动相关连线
     
    // var x=parseInt(moveobj.getAttribute("x"))+parseInt(moveobj.width)/2;
     //var y=parseInt(moveobj.getAttribute("y"))+parseInt(moveobj.height)/2;
     var x=parseInt(moveobj.getAttribute("x"))+ckx+parseInt(moveobj.getAttribute("width"))/2;
 
     var y=parseInt(moveobj.getAttribute("y"))+cky+parseInt(moveobj.getAttribute("height"))/2;
     //alert(x+","+y);
    var fromLinks=moveobj.fromLinks;
     if(fromLinks!=null)
      for(var i=0;i<fromLinks.length;i++){
        fromLinks[i].setAttribute("x1",x);
        fromLinks[i].setAttribute("y1",y);
         //fromLinks[i].setAttribute("transform","translate("+ckx+","+cky+")");
        //dealLineWhenObjMove(fromLinks[i]);
      }
     var toLinks=moveobj.toLinks;
     if(toLinks!=null)
      for(var i=0;i<toLinks.length;i++){
        toLinks[i].setAttribute("x2",x);
        toLinks[i].setAttribute("y2",y);
        //toLinks[i].setAttribute("transform","translate("+ckx+","+cky+")");
        //dealLineWhenObjMove(toLinks[i]);
      }
    }

}

//方法1,使用translate方法进行相对移动.
function drago(evt,obj){
	
	  //获得事件的父对象(group)
	  var oc=evt.target;
	  var o=evt.target.parentNode;
		var d=document;
		//var d=document.getElementById('divsvg');
		//var d=getSVGDocument(svg);
		if(!evt)evt=window.event;
		
		//记录down点击的相对位置(注意,是相对svg/divsvg的位置)
		var x=evt.layerX?evt.layerX:evt.offsetX,y=evt.layerY?evt.layerY:evt.offsetY;
		//获得svg的初始位置,用于计算坐标
		var divsvg=document.getElementById('divsvg');
		var dtop=delPx(divsvg.style.top);
		var dleft=delPx(divsvg.style.left);
		
		
		//记录初始的位置信息
		var ttx=o.getAttribute("x");
		var tty=o.getAttribute("y");
		
	
		
		dealLineWhenChoose(o);
	
		
		if(o.setCapture)
			o.setCapture();
		else if(window.captureEvents)
			window.captureEvents(Event.MOUSEMOVE|Event.MOUSEUP);

    //opera的svg不会遮挡document的事件,但是ie会
		d.onmousemove=function(a){
			if(!a)a=window.event;
			if(!a.pageX)a.pageX=a.clientX;
			if(!a.pageY)a.pageY=a.clientY;
			
			//目标的相对位置(注意,要考虑svg的初始位置影响)
			var tx=a.pageX-x-dleft-ttx,ty=a.pageY-y-dtop-tty;
				
			
		
			//这个每次都是从最初位置开始移动。
			movdev(o,tx,ty);
		};

		d.onmouseup=function(){
			if(o.releaseCapture){
				
				o.releaseCapture();
			}
			else if(window.captureEvents)
				window.captureEvents(Event.MOUSEMOVE|Event.MOUSEUP);
			d.onmousemove=null;
			d.onmouseup=null;
		};

}


//方法1,使用translate方法进行相对移动.
function dragie(evt,obj){
	
	  //获得事件的父对象(group)
	  var oc=evt.target;
	  var o=evt.target.parentNode;
		var d=document;
		if(!evt)evt=window.event;
		
		
		//获得svg的初始位置,用于计算坐标
		var divsvg=document.getElementById('divsvg');
		var dtop=delPx(divsvg.style.top);
		var dleft=delPx(divsvg.style.left);
		
		
		//记录初始的位置信息(不用)
		var ttx=o.getAttribute("x");
		var tty=o.getAttribute("y");
		
		xx=evt.clientX;
    yy=evt.clientY;
		
		 var tran;
   var trans=o.getAttribute("transform");
   if(trans){
   	tran=trans.substring(10,trans.length-1);
   	var tranpara=tran.split(",");
   	ckleft=parseInt(tranpara[0]);
   	cktop=parseInt(tranpara[1]);
   }
   
		
	
		
		if(o.setCapture)
			o.setCapture();
		else if(window.captureEvents)
			window.captureEvents(Event.MOUSEMOVE|Event.MOUSEUP);
			
			dealLineWhenChoose(o);

    //opera的svg不会遮挡document的事件,ie需要设置成透明
		d.onmousemove=function(a){
			if(!a)a=window.event;
			if(!a.pageX)a.pageX=a.clientX;
			if(!a.pageY)a.pageY=a.clientY;
			
			//目标的相对位置(注意,要考虑svg的初始位置影响)
      //由于ie不能取到初始的offset,所以算法和opera不同,但是效果相同
      //var tx=a.pageX-x-dleft-ttx,ty=a.pageY-y-dtop-tty;
			var tx=a.pageX+ckleft-xx-dleft,ty=a.pageY+cktop-yy-dtop;
				
			
		
			//这个每次都是从最初位置开始移动。
			movdev(o,tx,ty);
		};

		d.onmouseup=function(){
			if(o.releaseCapture){
				
				o.releaseCapture();
			}
			else if(window.captureEvents)
				window.captureEvents(Event.MOUSEMOVE|Event.MOUSEUP);
			d.onmousemove=null;
			d.onmouseup=null;
		};

}

		

		
function delPx(pos){
	return (parseInt(pos.substring(0,pos.length-2)));
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值