因为要实现拖拽连线研究了一下基于extjs 和html5的不同实现方法
extjs底层的画图引擎是svg 不知道在html5大潮即将袭来的前夕一贯走在技术前沿的extjs开发团队没有自己封装基于html5的画图引擎,而是选择了svg 。
下边是花了不到一天的时间实现的任意点连线和拖动功能,代码没有优化,稍微乱了点
如果单纯应用canvas进行画图,拖拽是非常麻烦的,我们往往要基于第三方的画图类库,这里实现是基于kineticjs
为了测试方便我使用了双击事件控制拖动还是划线 。
代码
- <!DOCTYPE HTML>
- <html>
- <head>
- <style>
- body {
- margin: 0px;
- padding: 0px;
- }
- canvas {
- border: 1px solid #9C9898;
- }
- </style>
- <script type="text/javascript" src="ext/bootstrap.js"></script>
- <!-- ENDLIBS -->
- <script type="text/javascript" src="ext/ext-all-debug.js"></script>
- <script src="js/kinetic-v3.10.2.min.js"></script>
- <script>
- Ext.onReady(function(){
- /**
- 自动判断顶点连线算法
- */
- var stage=new Kinetic.Stage({
- container:'container',
- 1000,
- height:1000
- });
- var layer=new Kinetic.Layer();
- var flag=false;
- var imgArray=[];
- var lineArray=[];
- var tmpMoveImg=null;
- var loop=0;
- function Pos(x,y){
- this.x=x;
- this.y=y;
- };
- function LineImage(img,line){
- this.img=img;
- this.line=line;
- };
- function NewImage(img,opsArray){
- this.img=img;
- this.opsArray=opsArray;
- };
- var imgA= new Image();
- imgA.onload=function(){
- var imgObjA= createImage(imgA,100,100,100,100)
- var array=new Array();
- var na=new NewImage(imgObjA,array);
- imgArray.push(na);
- layer.add(imgObjA);
- stage.add(layer);
- }
- var imgB= new Image();
- imgB.onload=function(){
- var imgObjB= createImage(imgB,400,400,100,100)
- var array=new Array();
- var nb=new NewImage(imgObjB,array);
- imgArray.push(nb);
- layer.add(imgObjB);
- stage.add(layer);
- }
- var imgC= new Image();
- imgC.onload=function(){
- var imgObjC= createImage(imgC,700,100,100,100)
- var array=new Array();
- var nc=new NewImage(imgObjC,array);
- imgArray.push(nc);
- layer.add(imgObjC);
- stage.add(layer);
- }
- var rect=new Kinetic.Rect({
- x:0,
- y:0,
- 1000,
- height:1000,
- fill:'white',
- storke:'red',
- storkeWidth:5
- });
- layer.add(rect);
- imgA.src='img/db.png';
- imgB.src='img/mj.png';
- imgC.src="img/kt1.png";
- rect.on('dblclick',function(){
- if(loop%2==0){
- flag=true;
- for(var i=0;i<imgArray.length;i++){
- imgArray[i].img.setDraggable(false);
- }
- }else{
- flag=false;
- for(var i=0;i<imgArray.length;i++){
- imgArray[i].img.setDraggable(true);
- imgArray[i].img.on('mouseover',function(){
- var p=new Pos(this.getX(),this.getY());
- tmpMoveImg=getImgByPos(p);
- })
- imgArray[i].img.on('dragmove',function(){
- for(var j=0;j<tmpMoveImg.opsArray.length;j++){
- var realPoints=[];
- calculateStartEndPos(tmpMoveImg.opsArray[j].img,this,realPoints);
- var line= createLine(realPoints);
- var oldLine=tmpMoveImg.opsArray[j].line;
- var p=new Pos(tmpMoveImg.opsArray[j].img.getX(),tmpMoveImg.opsArray[j].img.getY());
- var oppoImg= getImgByPos(p);
- replaceOppoLine(oppoImg,oldLine,line);
- layer.remove(tmpMoveImg.opsArray[j].line);
- tmpMoveImg.opsArray[j].line=line;
- layer.add(line);
- layer.draw();
- realPoints=[];
- }
- layer.draw();
- })
- }
- }
- loop++;
- for(var i=0;i<imgArray.length;i++){
- var innerFlag=false;
- var points=[];//标记性的点,为了获取img 使用
- var realPoints=[];//真正计算后合理的划线点
- imgArray[i].img.on('mousedown',function(){
- if(flag){
- var pos= stage.getMousePosition();
- points.push(this.getX());
- points.push(this.getY());
- innerFlag=true;
- }
- });
- imgArray[i].img.on('mouseup',function(){
- if(flag&&innerFlag){
- var pos= stage.getMousePosition();
- points.push(this.getX());
- points.push(this.getY());
- var p=new Pos(points[0],points[1]);
- var op=new Pos(points[2],points[3]);
- var opImg=getImgByPos(p);
- var owImg=getImgByPos(op);
- if(opImg!=owImg){
- calculateStartEndPos(opImg.img,owImg.img,realPoints);
- var line= createLine(realPoints);
- var opLine=new LineImage(opImg.img,line);
- var owLine=new LineImage(owImg.img,line);
- owImg.opsArray.push(opLine);
- opImg.opsArray.push(owLine);
- flag=false;
- innerFlag=false;
- points=[];
- realPoints=[];
- layer.add(line);
- layer.draw();
- }
- }
- });
- }
- })
- /**
- * 通过坐标获取Img对象
- */
- function getImgByPos(pos){
- for(var i=0;i<imgArray.length;i++){
- if(imgArray[i].img.getX()==pos.x&&imgArray[i].img.getY()==pos.y){
- return imgArray[i];
- }
- }
- }
- /**
- * 替换对方中line
- */
- function replaceOppoLine(imgObj,oldLine,newLine){
- for(var i=0;i<imgObj.opsArray.length;i++){
- if(imgObj.opsArray[i].line==oldLine){
- imgObj.opsArray[i].line=newLine;
- }
- }
- }
- /**
- 划线
- */
- function createLine(points){
- var line=new Kinetic.Line({
- points:points,
- stroke:'bule',
- strokeWidth:5,
- lineCap:'round',
- lineJoin:'round'
- });
- return line;
- }
- /**
- * 计算划线的开始坐标
- */
- function calculateStartEndPos(imgStart,imgEnd,realPoints){
- var realSx=0;
- var realSy=0;
- var realEx=0;
- var realEy=0;
- var sx=imgStart.getX();
- var sy=imgStart.getY();
- var swidth=imgStart.getWidth();
- var sheight=imgStart.getHeight();
- var ex=imgEnd.getX();
- var ey=imgEnd.getY();
- var ewidth=imgEnd.getWidth();
- var eheight=imgEnd.getHeight();
- var arrayx=calculateX(sx,swidth,ex,ewidth );
- var arrayy=calculateY(sy,sheight,ey,eheight );
- realPoints.push(arrayx[0]);
- realPoints.push(arrayy[0]);
- realPoints.push(arrayx[1]);
- realPoints.push(arrayy[1]);
- }
- /**
- 计算开始和结束节点x坐标
- */
- function calculateX(sx,swidth,ex,ewidth ){
- var arrayX=[];
- if(sx>ex){
- arrayX.push(sx);
- arrayX.push(ex+ewidth);
- }else if(sx==ex){
- arrayX.push(sx+(swidth/2));
- arrayX.push(sx+(ewidth/2));
- }else{
- arrayX.push(sx+swidth);
- arrayX.push(ex);
- }
- return arrayX;
- }
- /**
- 计算开始和结束节点y坐标
- */
- function calculateY(sy,sheight,ey,eheight ){
- var arrayY=[];
- if(sy>ey){
- arrayY.push(sy+(sheight/2));
- arrayY.push(ey+(eheight/2));
- }else if(sy==ey){
- arrayY.push(sy+(sheight/2));
- arrayY.push(sy+(eheight/2));
- }else{
- arrayY.push(sy+(sheight/2));
- arrayY.push(ey+(eheight/2));
- }
- return arrayY;
- }
- /**
- 画图
- */
- function createImage(img,x,y,width,height){
- var imgObj=new Kinetic.Image({
- x:x,
- y:y,
- width,
- height:height,
- draggable:true,
- image:img
- });
- imgObj.on("mouseover", function(){
- document.body.style.cursor = "pointer";
- });
- imgObj.on("mouseout", function(){
- document.body.style.cursor = "default";
- });
- return imgObj
- }
- });
- </script>
- </head>
- <body>
- <div id="container"></div>
- </body>
- </html>
- <img alt="" src="http://dl.iteye.com/upload/attachment/0070/8176/f9bb5503-b35b-3a45-abb1-0241a1495665.png">
- <img alt="" src="http://dl.iteye.com/upload/attachment/0070/8178/54c788d0-1395-3824-aea1-280b70b6f523.png">
效果如下
代码里还有一项基于extjs4 的实现和纯html5 canvas 的实现