效果如下,拖动任意一个,连线会随着动,
(连线连的比较随意,后期换别的版本了,就没继续做下去)
1.1 支持任意添加
1.2 支持右键删除
1.3 支持联动
使用说明:
1.点击图片添加图片
2.进入连线模式侯才可以连线
<!DOCTYPE html>
<html>
<head>
<title>鼠标滚轮</title>
<meta charset="utf-8">
<style>
canvas {
border: 1px dashed black;
}
</style>
<script src="js/fabric.js"></script>
<script src="js/jquery-1.11.3.js"></script>
<script src="js/jquery.mousewheel.js"></script>
<script src="contextMenu/jquery.ui.position.min.js" type="text/javascript"></script>
<script src="contextMenu/jquery.contextMenu.js" type="text/javascript"></script>
<link href="contextMenu/jquery.contextMenu.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div>非连接模式下,按住alt 才可拖动画布</div>
<canvas id="canvas" width="600" height="600"></canvas>
<div id="contextmenu-output"></div>
<div>
<button id="addPic" onclick="addPic()">图片</button>
<button id="addLine" onclick="addLine()">连线模式</button>
</div>
<script>
var canvas;
//是否拖动
var panning = false;
//连线模式
var ligature = false;
var lineNum;
var selectObj;
canvas = new fabric.Canvas('canvas');
//鼠标按下
canvas.on('mouse:down', function (e) {
if(ligature){ //连线模式
//点击位置坐标
var pointering = canvas.getPointer(event.originalEvent);
var inner = false;
var objects = canvas.getObjects();
var selected;
//定义被点击物体的信息
var minLeft;
var maxLeft;
var minTop;
var maxTop;
var w;
var h;
for (var i = objects.length - 1; i >= 0; i--) {
var obj = objects[i];
minLeft = obj.left;
maxLeft = obj.left+(obj.width)*obj.scaleX;
minTop = obj.top;
maxTop = obj.top+(obj.height)*obj.scaleY;
w = obj.width*obj.scaleX;
h = obj.height*obj.scaleY;
if(pointering.x>minLeft && pointering.x<maxLeft && pointering.y>minTop && pointering.y<maxTop){
inner = true;
selected = obj;
break;
}
}
if(inner){ //点击到物体上后
if (lineNum == undefined){ //第一次点击到物体上先记录信息
lineNum = [minLeft,maxLeft,minTop,maxTop,w,h];
selectObj = selected;
}else{ //第二次点击后画线
var startX,startY,endX,endY;
var line;
if( lineNum[1]<minLeft || lineNum[0]>=maxLeft ){//连接物在左侧或右侧
if(lineNum[1]<minLeft){
startX = lineNum[1];
startY = lineNum[2]+lineNum[5]/2;
endX = minLeft;
endY = minTop+h/2;
}else{
startX = lineNum[0];
startY = lineNum[2] + lineNum[5]/2;
endX = maxLeft;
endY = minTop + h/2;
}
var middleX = (endX - startX)/2 + startX;
var middleY1 = startY;
var middleY2 = endY;
line = makeLine('M '+startX+' '+startY+' L '+middleX+' '+middleY1+' L '+middleX+' '+middleY2+' L '+endX+' '+endY,[selected,selectObj]);
}else {
if(lineNum[2]>minTop){
startX = lineNum[0]+ lineNum[4]/2;
startY = lineNum[2];
endX = minLeft+ w/2;
endY = maxTop;
}else if(lineNum[3]<minTop){
startX = lineNum[0]+ lineNum[4]/2;
startY = lineNum[3];
endX = minLeft+ w/2;
endY = minTop;
}
middleY = startY+ (endY - startY)/2;
middleX1 = startX;
middleX2 = endX;
line = makeLine('M '+startX+' '+startY+' L '+middleX1+' '+middleY+' L '+middleX2+' '+middleY+' L '+endX+' '+endY,[selected,selectObj]);
}
lineNum = undefined;
canvas.add(line);
selected.lineGroup.push(line);
selectObj.lineGroup.push(line);
}
}else{ //点击空白,清空以一次点击信息
lineNum = undefined;
}
}else { //非连接模式下 可以拖动画布
//按住alt键才可拖动画布
if(e.e.altKey) {
panning = true;
canvas.selection = false;
}
}
console.log('数据结构:');
console.log(canvas._objects);
console.log('________________');
});
//鼠标抬起
canvas.on('mouse:up', function (e) {
panning = false;
canvas.selection = true;
var currObj = e.target;
if(currObj && !ligature && currObj.lineGroup!=''){
//被拖动物体的lineGroup
var currObjLineGroup = currObj.lineGroup;
if(currObjLineGroup){
//遍历拖动的图片上的lineGroup
for( var i = (currObjLineGroup.length - 1); i >= 0; i-- ){
var currentLine = currObjLineGroup[i];
//每根线对应两个图片
var innerPic = currObjLineGroup[i].pic;
//用于存放需要重新绘制线的两个物体
var drawObj = [[],[]];
var lineObjGroup = [];
//去掉这两个图片里面关于这条线的数据
for( var j = 1; j>=0; j--){
//图片里面对应的lineGroup
for( var m = (innerPic[j].lineGroup.length -1);m>=0;m--){
if(innerPic[j].lineGroup[m] == currentLine){
innerPic[j].lineGroup.splice(m,1);
}
}
lineObjGroup.push(innerPic[j]);
// 0 1 2 3 4 5
// minleft, maxleft, minTop, maxTop, w, h
drawObj[j] = [innerPic[j].left,innerPic[j].left+(innerPic[j].width)*innerPic[j].scaleX,innerPic[j].top,innerPic[j].top+(innerPic[j].height)*innerPic[j].scaleY,innerPic[j].width*innerPic[j].scaleX,innerPic[j].height*innerPic[j].scaleY];
}
//去掉旧线
canvas.remove(currentLine);
//根据新位置画线
var startX,startY,endX,endY;
var line;
if( drawObj[0][1]<drawObj[1][0] || drawObj[0][0]>= drawObj[1][1] ){
if(drawObj[0][1]<drawObj[1][0]){
startX = drawObj[0][1];
startY = drawObj[0][2]+drawObj[0][5]/2;
endX = drawObj[1][0];
endY = drawObj[1][2]+drawObj[1][5]/2;
}else{
startX = drawObj[0][0];
startY = drawObj[0][2] + drawObj[0][5]/2;
endX = drawObj[1][1];
endY = drawObj[1][2] + drawObj[1][5]/2;
}
var middleX = (endX - startX)/2 + startX;
var middleY1 = startY;
var middleY2 = endY;
line = makeLine('M '+startX+' '+startY+' L '+middleX+' '+middleY1+' L '+middleX+' '+middleY2+' L '+endX+' '+endY,lineObjGroup);
}else {
if(drawObj[0][2]>drawObj[1][2]){
startX = drawObj[0][0]+ drawObj[0][4]/2;
startY = drawObj[0][2];
endX = drawObj[1][0]+ drawObj[1][4]/2;
endY = drawObj[1][3];
}else if(drawObj[0][3]<drawObj[1][2]){
startX = drawObj[0][0]+ drawObj[0][4]/2;
startY = drawObj[0][3];
endX = drawObj[1][0]+ drawObj[1][4]/2;
endY = drawObj[1][2];
}
middleY = startY+ (endY - startY)/2;
middleX1 = startX;
middleX2 = endX;
line = makeLine('M '+startX+' '+startY+' L '+middleX1+' '+middleY+' L '+middleX2+' '+middleY+' L '+endX+' '+endY,lineObjGroup);
}
canvas.add(line);
lineObjGroup[0].lineGroup.push(line);
lineObjGroup[1].lineGroup.push(line);
}
}
}
});
//鼠标移动
canvas.on('mouse:move', function (e) {
if (panning && e && e.e) {
var delta = new fabric.Point(e.e.movementX, e.e.movementY);
canvas.relativePan(delta);
}
});
function makeLine(info,pic) {
return new fabric.Path(info, {
fill: 'transparent',
stroke: 'red',
strokeWidth: 5,
selectable: false,
type: 'line',
pic: pic
});
}
function addPic() {
fabric.Image.fromURL('timg.jpg', function(oImg) {
oImg.scale(0.1);//图片缩小10倍
oImg.hasBorders = false;
oImg.lineGroup = [];
oImg.type='pic';
canvas.add(oImg);
});
}
//鼠标滚轮监听
$(".upper-canvas").mousewheel(function(event) {
var zoom = (event.deltaY > 0 ? 0.1 : -0.1) + canvas.getZoom();
zoom = Math.max(0.1,zoom); //最小为原来的1/10
zoom = Math.min(3,zoom); //最大是原来的3倍
var zoomPoint = new fabric.Point(event.pageX, event.pageY);
canvas.zoomToPoint(zoomPoint, zoom);
});
//在canvas上层对象上添加右键事件监听
$(".upper-canvas").contextmenu(onContextmenu);
//初始化右键菜单
$.contextMenu({
selector: '#contextmenu-output',
trigger: 'none',
build: function($trigger, e) {
//构建菜单项build方法在每次右键点击会执行
return {
callback: contextMenuClick,
items: contextMenuItems
};
},
});
//右键点击事件响应
function onContextmenu(event) {
var pointer = canvas.getPointer(event.originalEvent);
var objects = canvas.getObjects();
for (var i = objects.length - 1; i >= 0; i--) {
var object = objects[i];
//判断该对象是否在鼠标点击处
if (canvas.containsPoint(event, object)) {
//选中该对象
canvas.setActiveObject(object);
//显示菜单
showContextMenu(event, object);
continue;
}
}
//阻止系统右键菜单
event.preventDefault();
return false;
}
//右键菜单项点击
function showContextMenu(event, object) {
//定义右键菜单项
contextMenuItems = {
"delete": {name: "删除", icon: "delete", data: object}
};
//右键菜单显示位置
var position = {
x: event.clientX,
y: event.clientY
}
$('#contextmenu-output').contextMenu(position);
}
//右键菜单项点击
function contextMenuClick(key, options) {
if(key == "delete") {
//得到对应的object并删除
var object = contextMenuItems[key].data;
if(object.type == 'line'){
var objects = object.pic;
for (var i = 0; i < 2; i++) {
var innerLine = objects[i].lineGroup;
for( var j = 0;j< innerLine.length;j++ ){
if(innerLine[j] == object){
innerLine.splice(j,1);
}
}
}
}else{
var objects = object.lineGroup;
//首先遍历删除图片内对应的连线有哪些
for (var i = (objects.length-1); i >=0 ; i--) {
var deleteLine = objects[i];
var innerPic = deleteLine.pic;
//遍历对应线两端连接的图片
for( var j =0; j < 2; j++ ){
//删除另一端图片内所包含的该线的数据
for( var m =0;m<innerPic[j].lineGroup.length;m++){
if(innerPic[j].lineGroup[m] == deleteLine){
innerPic[j].lineGroup.splice(m,1);
}
}
}
canvas.remove(deleteLine);
}
}
canvas.remove(object);
}
}
//连线模式
function addLine() {
ligature = !ligature;
if(ligature){
$('#addLine').text('退出连接模式!');
$('#canvas').css('background','#ff9e3d');
$('#addPic').attr({"disabled":"disabled"});
lineNum = undefined;
var objects = canvas.getObjects();
for (var i = objects.length - 1; i >= 0; i--) {
objects[i].selectable = false;
}
}else{
$('#addLine').text('连接模式');
$('#canvas').css('background','#fff');
$('#addPic').attr({"disabled":false});
var objects = canvas.getObjects();
for (var i = objects.length - 1; i >= 0; i--) {
objects[i].selectable = true;
}
}
}
</script>
</body>
</html>