自动折线,自动判断起始点坐标,拖拽位置变换,大小拖拽,箭头指向等功能,这个版本稍微复杂一点,
还有个简单版本的实现http://zha-zi.iteye.com/blog/1586814 这个应该比较容易理解坐标换算不太多
body {
margin: 0px;
padding: 0px;
}
canvas {
border: 1px solid #9C9898;
}
Ext.onReady(function(){
/**
自动折叠连线算法
*/
var stage=new Kinetic.Stage({
container:'container',
width:1000,
height:1000
});
/**
箭头角度
*/
var arrowAngle=30;
/**
箭头半径
*/
var arrowRadius=5;
/**
箭头长度
*/
var arrowLenght=10;
/**
表示方向
*/
var E="E";
var W="W";
var S="S";
var N="N";
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;
};
/**
img 图像
lineArrow 带有箭头的line
flag 图像与箭头的指向关系
*/
function LineImage(img,lineArrow,flag){
this.img=img;
this.lineArrow=lineArrow;
this.flag=flag
};
function LineArrow(line,arrow){
this.line=line;
this.arrow=arrow;
};
function NewImage(img,opsArray,group){
this.img=img;
this.group=group;
this.opsArray=opsArray;
};
var imgA= new Image();
var imgObjA;
var groupA;
imgA.οnlοad=function(){
imgObjA= createImage(imgA,100,100,100,100)
var array=new Array();
groupA=new Kinetic.Group({
draggable:true
});
groupA.add(imgObjA);
layer.add(groupA);
addAnchor(groupA, 100, 100,"topLeft");
addAnchor(groupA, 200, 100,"topRight");
addAnchor(groupA, 200, 200,"bottomRight");
addAnchor(groupA, 100, 200,"bottomLeft");
var na=new NewImage(imgObjA,array,groupA);
imgArray.push(na);
stage.add(layer);
}
var imgB= new Image();
var imgObjB;
var groupB;
imgB.οnlοad=function(){
imgObjB= createImage(imgB,400,400,100,100)
var array=new Array();
groupB=new Kinetic.Group({
draggable:true
});
groupB.add(imgObjB);
layer.add(groupB);
addAnchor(groupB, 400, 400,"topLeft");
addAnchor(groupB, 500, 400,"topRight");
addAnchor(groupB, 500, 500,"bottomRight");
addAnchor(groupB, 400, 500,"bottomLeft");
var nb=new NewImage(imgObjB,array,groupB);
imgArray.push(nb);
stage.add(layer);
}
var imgC= new Image();
var imgObjC;
var groupC;
imgC.οnlοad=function(){
imgObjC= createImage(imgC,700,100,100,100)
var array=new Array();
groupC=new Kinetic.Group({
draggable:true
});
groupC.add(imgObjC);
layer.add(groupC);
addAnchor(groupC, 700, 100,"topLeft");
addAnchor(groupC, 800, 100,"topRight");
addAnchor(groupC, 800, 200,"bottomRight");
addAnchor(groupC, 700, 200,"bottomLeft");
var nc=new NewImage(imgObjC,array,groupC);
imgArray.push(nc);
stage.add(layer);
}
var rect=new Kinetic.Rect({
x:0,
y:0,
width: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[i].group.setDraggable(false);
}
}else{
flag=false;
for(var i=0;i
imgArray[i].group.setDraggable(true);
imgArray[i].img.on('mouseover',function(){
var p=new Pos(this.getAbsolutePosition().x,this.getAbsolutePosition().y);
tmpMoveImg=getImgByPos(p);
});
imgArray[i].group.on('dragmove',function(){
for(var j=0;j
var realPoints=[];
if(tmpMoveImg.opsArray[j].flag){
calculateStartEndPos(tmpMoveImg.opsArray[j].img,this.children[0],realPoints);
}else{
calculateStartEndPos(this.children[0],tmpMoveImg.opsArray[j].img,realPoints);
}
tmpMoveImg.opsArray[j].lineArrow.line.setPoints(realPoints);
var arrowPoint= calculateArrowPointsByPoints(realPoints);
tmpMoveImg.opsArray[j].lineArrow.arrow.setPoints(arrowPoint);
layer.draw();
realPoints=[];
}
layer.draw();
});
imgArray[i].group.on('dragmove',function(){
for(var j=0;j
//lineArray[j].hide();
//moveLineToTarget(lineArray[j])
}
});
}
}
loop++;
for(var i=0;i
var innerFlag=false;
var points=[];//标记性的点,为了获取img 使用
var realPoints=[];//真正计算后合理的划线点
imgArray[i].img.on('mousedown',function(){
if(flag){
var pos= stage.getMousePosition();
points=[];
points.push(this.getAbsolutePosition().x);
points.push(this.getAbsolutePosition().y);
innerFlag=true;
}
});
imgArray[i].img.on('mouseup',function(){
if(flag&&innerFlag){
var pos= stage.getMousePosition();
points.push(this.getAbsolutePosition().x);
points.push(this.getAbsolutePosition().y);
//起始点
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 lineArrow= createLine(realPoints);
var opLine=new LineImage(opImg.img,lineArrow,true);
var owLine=new LineImage(owImg.img,lineArrow,false);
owImg.opsArray.push(opLine);
opImg.opsArray.push(owLine);
flag=false;
innerFlag=false;
points=[];
realPoints=[];
lineArray.push(lineArrow);
layer.add(lineArrow.line);
layer.add(lineArrow.arrow);
layer.draw();
bandEventToLine(lineArrow.line);
}
}
});
}
})
/**
* 通过坐标获取Img对象
*/
function getImgByPos(pos){
for(var i=0;i
if(imgArray[i].img.getAbsolutePosition().x==pos.x&&imgArray[i].img.getAbsolutePosition().y==pos.y){
return imgArray[i];
}
}
}
/**
* 替换对方中line
*/
function replaceOppoLine(imgObj,oldLine,newLine){
for(var i=0;i
if(imgObj.opsArray[i].line==oldLine){
imgObj.opsArray[i].line=newLine;
}
}
}
/**
* 计算划线的开始坐标
*/
function calculateStartEndPos(imgStart,imgEnd,realPoints){
var realSx=0;
var realSy=0;
var realEx=0;
var realEy=0;
var sx=imgStart.getAbsolutePosition().x;
var sy=imgStart.getAbsolutePosition().y;
var swidth=imgStart.getWidth();
var sheight=imgStart.getHeight();
var ex=imgEnd.getAbsolutePosition().x;
var ey=imgEnd.getAbsolutePosition().y;
var ewidth=imgEnd.getWidth();
var eheight=imgEnd.getHeight();
var array=calculateXY(sy,sheight,ey,eheight ,sx,swidth,ex,ewidth);
var crossArray=null;
if((array[0]!=array[2])&&(array[1]!=array[3])){
var crossArray= calculateCrossPoints(array,sy,sheight,ey,eheight ,sx,swidth,ex,ewidth);
}
realPoints.push(array[0]);
realPoints.push(array[1]);
if(crossArray!=null)
for(var i=0;i
realPoints.push(crossArray[i]);
}
realPoints.push(array[2]);
realPoints.push(array[3]);
}
/**
计算连线开始和结束坐标的位置
*/
function calculateXY(sy,sheight,ey,eheight,sx,swidth,ex,ewidth ){
var array=[];
if(sy==ey){
if(sx>ex){
array.push(sx);
array.push(sy+(sheight/2));
array.push(ex+ewidth);
array.push(sy+(eheight/2));
}else{
array.push(sx+swidth);
array.push(sy+(sheight/2));
array.push(ex);
array.push(sy+(eheight/2));
}
}else{
if(sy>ey&&(sy-ey>sheight)){
if(sx>ex){
if(sx-ex
array.push(sx);
array.push(sy+(sheight/2));
array.push(ex);
array.push(ey+eheight/2);
}else{
array.push(sx);
array.push(sy+(sheight/2));
array.push(ex+(ewidth/2));
array.push(ey+eheight);
}
}else if(sx==ex){
array.push(sx+(swidth/2));
array.push(sy);
array.push(ex+(ewidth/2));
array.push(ey+eheight);
}else{
if(ex-sx
array.push(sx);
array.push(sy+(sheight/2));
array.push(ex);
array.push(ey+eheight/2);
}else{
array.push(sx+swidth);
array.push(sy+(sheight/2));
array.push(ex+(ewidth/2));
array.push(ey+eheight);
}
}
}else if(syeheight)){
if(sx>ex){
if(sx-ex
array.push(sx);
array.push(sy+sheight/2);
array.push(ex);
array.push(ey+eheight/2);
}else{
array.push(sx+(swidth/2));
array.push(sy+sheight);
array.push(ex+ewidth);
array.push(ey+(eheight/2));
}
}else if(sx==ex){
array.push(sx+(swidth/2));
array.push(sy+sheight);
array.push(ex+(ewidth/2));
array.push(ey);
}else{
if(ex-sx
array.push(sx);
array.push(sy+sheight/2);
array.push(ex);
array.push(ey+eheight/2);
}else{
array.push(sx+(swidth/2));
array.push(sy+sheight);
array.push(ex);
array.push(ey+(eheight/2));
}
}
}else{
if((syey&&(sy-ey
array.push(sx+swidth/2);
array.push(sy);
array.push(ex+ewidth/2);
array.push(ey);
}
}
}
return array;
}
/**
计算折叠点的位置
*/
function calculateCrossPoints(array,sy,sheight,ey,eheight ,sx,swidth,ex,ewidth){
var pointsArray=[];
var x=array[0];
var y=array[1];
var x1=array[2];
var y1=array[3];
var f=false;
if((x-x1)>0&&(y-y1)>0){
f=true;
}
if((x1-x)>0&&(y1-y)>0){
f=true;
}
/**
y轴的多个折叠点
*/
if((sy>ey&&sy-ey<=sheight)||(sy
if(sy>ey&&sy-ey<=sheight){
pointsArray.push(x);
pointsArray.push(y1-sheight);
pointsArray.push(x1);
pointsArray.push(y1-sheight);
}else if(sy
pointsArray.push(x);
pointsArray.push(y-eheight);
pointsArray.push(x1);
pointsArray.push(y-eheight);
}
}else if((sx>ex&&sx-ex<=sheight/2)||(sx
/**
x轴的多个折点
*/
//x= sx-swidth/2
//y=y+sheight/2
if(sx-ex
pointsArray.push(sx-ewidth);
pointsArray.push(sy+sheight/2);
pointsArray.push(sx-ewidth);
pointsArray.push(ey+eheight/2);
}else if(ex-sx
pointsArray.push(ex-swidth);
pointsArray.push(sy+sheight/2);
pointsArray.push(ex-swidth);
pointsArray.push(ey+eheight/2);
}
}else{
/**
单个折叠点
*/
if(f){
if(x
pointsArray.push(x);
}else{
pointsArray.push(x1);
}
if(y
pointsArray.push(y1);
}else{
pointsArray.push(y);
}
}else{
if(x
pointsArray.push(x1);
}else{
pointsArray.push(x);
}
if(y
pointsArray.push(y1);
}else{
pointsArray.push(y);
}
}
}
return pointsArray;
}
function createImage(img,x,y,width,height){
var imgObj=new Kinetic.Image({
x:x,
y:y,
width:width,
height:height,
//draggable:true,
image:img,
name:"image",
});
imgObj.on("mouseover", function(){
document.body.style.cursor ="pointer";
});
imgObj.on("mouseout", function(){
document.body.style.cursor ="default";
});
return imgObj
}
/**
根据points 节点数组划线
*/
function createLine(points){
var line=new Kinetic.Line({
points:points,
stroke:'green',
strokeWidth:2,
lineCap:'round',
lineJoin:'round'
});
var lenght=points.length;
var x=points[lenght-4];
var y=points[lenght-3];
var x1=points[lenght-2];
var y1=points[lenght-1];
var arrow=createArrow(calculateArrowPosition(x1,y1,calculateArrowAspect(x,y,x1,y1)),"black");
var la =new LineArrow(line,arrow);
return la;
}
function bandEventToLine(line){
line.saveData();
line.on("mouseover", function(){
document.body.style.cursor ="pointer";
});
line.on("mouseout", function(){
document.body.style.cursor ="default";
});
}
/**
通过line计算 arrow 的points 数组
*/
function calculateArrowPointsByLine(line){
var points=line.getPoints();
var lenght=points.length;
var x=points[lenght-4];
var y=points[lenght-3];
var x1=points[lenght-2];
var y1=points[lenght-1];
return calculateArrowPosition(x1,y1,calculateArrowAspect(x,y,x1,y1));
}
function calculateArrowPointsByPoints(points){
var lenght=points.length;
var x=points[lenght-4];
var y=points[lenght-3];
var x1=points[lenght-2];
var y1=points[lenght-1];
return calculateArrowPosition(x1,y1,calculateArrowAspect(x,y,x1,y1));
}
/**
计算箭头朝向
*/
function calculateArrowAspect(x,y,x1,y1){
if(x==x1){
if(y>y1){
return N;
}else{
return S;
}
}else if(y==y1){
if(x>x1){
return W;
}else{
return E;
}
}
}
/**
计算箭头具体位置
*/
function calculateArrowPosition(x,y,aspect){
var points=[];
switch(aspect){
case N:
points.push(x);
points.push(y);
points.push(x-arrowRadius);
points.push(y+arrowLenght);
points.push(x+arrowRadius);
points.push(y+arrowLenght);
break;
case S:
points.push(x);
points.push(y);
points.push(x-arrowRadius);
points.push(y-arrowLenght);
points.push(x+arrowRadius);
points.push(y-arrowLenght);
break;
case E:
points.push(x);
points.push(y);
points.push(x-arrowLenght);
points.push(y+arrowRadius);
points.push(x-arrowLenght);
points.push(y-arrowRadius);
break;
case W:
points.push(x);
points.push(y);
points.push(x+arrowLenght);
points.push(y+arrowRadius);
points.push(x+arrowLenght);
points.push(y-arrowRadius);
break;
}
return points;
}
function createArrow(points,fill){
var arrow=new Kinetic.Polygon({
points: points,
fill: fill,
stroke:"black",
strokeWidth: 1
});
return arrow;
}
function addAnchor(group,x,y,name){
var stage=group.getStage();
var layer=group.getLayer();
var anchor=new Kinetic.Circle({
x:x,
y:y,
stroke:'#666',
fill:'green',
radius:1,
name:name,
draggable:true
});
anchor.on('dragmove',function(){
update(group, this);
layer.draw();
});
anchor.on('dragend',function(){
group.setDraggable(true);
layer.draw();
});
anchor.on('mousedown touchstar',function(){
group.setDraggable(false);
//this.moveToTop();
});
anchor.on('mouseover',function(){
var layer = this.getLayer();
document.body.style.cursor ="pointer";
this.setRadius(3);
layer.draw();
});
anchor.on('mouseout',function(){
var layer = this.getLayer();
document.body.style.cursor ="default";
this.setRadius(1);
layer.draw();
});
group.add(anchor);
}
function update(group,activeAnchor){
var topLeft=group.get(".topLeft")[0];
var topRight=group.get(".topRight")[0];
var bottomLeft=group.get(".bottomLeft")[0];
var bottomRight=group.get(".bottomRight")[0];
var image=group.children[0];
switch(activeAnchor.getName()){
case"topLeft":
topRight.attrs.y = activeAnchor.attrs.y;
bottomLeft.attrs.x = activeAnchor.attrs.x;
break;
case"topRight":
topLeft.attrs.y = activeAnchor.attrs.y;
bottomRight.attrs.x = activeAnchor.attrs.x;
break;
case"bottomRight":
bottomLeft.attrs.y = activeAnchor.attrs.y;
topRight.attrs.x = activeAnchor.attrs.x;
break;
case"bottomLeft":
bottomRight.attrs.y = activeAnchor.attrs.y;
topLeft.attrs.x = activeAnchor.attrs.x;
break;
}
image.setPosition(topLeft.attrs.x, topLeft.attrs.y);
image.setSize(topRight.attrs.x - topLeft.attrs.x, bottomLeft.attrs.y - topLeft.attrs.y);
}
});