Im working on a project of building a editor, i am using the Fabric.js, but i don know how to make the canvas object auto align.
Is there any example of making canvas object auto align with another object like this?
image of snap example
auto snap example from other site
link here:
auto snap example site
可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
回答1:
I was working on the same thing. This seems to be a pretty common feature request so I thought I'd share what I worked out. It could use some refinement. For instance, I've noticed if you scale the red box, the scale is not applied and it doesn't align right. However, I think it demonstrates the basic principal well and you can elaborate on it to fit your needs.
(Note: 8/1/2017: Working to place a more comprehensive code base on GitHub. (https://github.com/JerrodV/FabricObjectAlignment) More Details Soon!)
You can view the fiddle here
Html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<canvas id="c" height="600" width="600" style="border:1px solid #c1c1c1;"></canvas>
</div>
</form>
<script src="Scripts/jquery-3.1.1.min.js"></script>
<script src="Scripts/fabric.min.js"></script>
<script src="Scripts/default.js"></script>
</body>
</html>
Javascript:
Def = {
canvas: null,
rect: null,
lines: {
top: null,
left: null,
right: null,
bottom: null
},
init: function () {
Def.canvas = new fabric.Canvas('c');
Def.canvas.on('object:moving', Def.events.objectMoving);
Def.canvas.add(new fabric.Rect({
height: 100,
width: 100,
top: 100,
left: 200,
fill: 'black',
selectable: false
}));
Def.canvas.add(new fabric.Rect({
height: 100,
width: 100,
top: 300,
left: 100,
fill: 'black',
selectable: false
}));
Def.rect = new fabric.Rect({
height: 100,
width: 100,
top: 200,
left: 250,
fill: 'red'
});
Def.canvas.add(Def.rect);
},
events: {
objectMoving: function (e) {
//Get the object being manipulated
var obj = e.target;
//Set up an object representing its current position
var curPos = {
top: parseInt(obj.get('top')),
left: parseInt(obj.get('left')),
right: parseInt(obj.get('left') + obj.get('width')),
bottom: parseInt(obj.get('top') + obj.get('height'))
};
//Set up an object that will let us be able to keep track of newly created lines
var matches = {
top: false,
left: false,
right: false,
bottom: false
}
//Get the objects from the canvas
var objects = Def.canvas.getObjects();
//For each object
for (var i in objects) {
//If the object we are looing at is a line or the object being manipulated, skip it
if (objects[i] === obj || objects[i].get('type') === 'line') { continue; }
//Set up an object representing the position of the canvas object
var objPos = {
top: parseInt(objects[i].get('top')),
left: parseInt(objects[i].get('left')),
right: parseInt(objects[i].get('left') + obj.get('width')),
bottom: parseInt(objects[i].get('top') + obj.get('height'))
}
//Look at all 4 sides of the object and see if the object being manipulated aligns with that side.
//Top////////////////////////////////////
if (Def.inRange(objPos.top, curPos.top)) {
//We match. If we don't already have aline on that side, add one.
if (!Def.lines.top) {
Def.drawLine('top', objPos.top);
//Keep track of the fact we found a match so we don't remove the line prematurely.
matches.top = true;
//Snap the object to the line
obj.set('top', objPos.top).setCoords();
}
}
//Left////////////////////////////////////
if (Def.inRange(objPos.left, curPos.left)) {
if (!Def.lines.left) {
Def.drawLine('left', objPos.left);
matches.left = true;
obj.set('left', objPos.left).setCoords();
}
}
//Right////////////////////////////////////
if (Def.inRange(objPos.right, curPos.right)) {
if (!Def.lines.right) {
Def.drawLine('right', objPos.right);
matches.right = true;
obj.set('left', objPos.right - objects[i].get('width')).setCoords();
}
}
//Bottom////////////////////////////////////
if (Def.inRange(objPos.bottom, curPos.bottom)) {
if (!Def.lines.bottom) {
Def.drawLine('bottom', objPos.bottom);
matches.bottom = true;
obj.set('top', objPos.bottom - objects[i].get('height')).setCoords();
}
}
//Look at the side we matched on. If we did not match, and we have a line, remove the line.
for (var j in matches) {
var m = matches[j];
var line = Def.lines[j];
if (!m && line) {
Def.canvas.remove(line);
Def.lines[j] = null;
}
}
}
Def.canvas.renderAll();
}
},
drawLine: function (side, pos) {
var ln = null
switch (side) {
case 'top':
ln = new fabric.Line([Def.canvas.get('width'), 0, 0, 0], {
left: 0,
top: pos,
stroke: 'rgb(178, 207, 255)'
});
Def.lines.top = ln;
break;
case 'left':
ln = new fabric.Line([0, Def.canvas.get('height'), 0, 0], {
left: pos,
top: 0,
stroke: 'rgb(178, 207, 255)'
});
Def.lines.left = ln;
break;
case 'right':
ln = new fabric.Line([0, Def.canvas.get('height'), 0, 0], {
left: pos,
top: 0,
stroke: 'rgb(178, 207, 255)'
});
Def.lines.right = ln;
break;
case 'bottom':
ln = new fabric.Line([Def.canvas.get('width'), 0, 0, 0], {
left: 0,
top: pos,
stroke: 'rgb(178, 207, 255)'
});
Def.lines.bottom = ln;
break;
}
Def.canvas.add(ln).renderAll();
},
alignTolerance : 6,
inRange: function (val1, val2) {
if ((Math.max(val1, val2) - Math.min(val1, val2)) <= Def.alignTolerance) { return true; }
else { return false; }
}
};
$(Def.init);
I hope you find this useful. Good Luck!