我一直试图在边界内保持一个对象(在画布上用布料js构建).它是在移动和旋转它时实现的.我从Move object within canvas boundary limit获得了帮助以实现这一目标.但是当我开始缩放对象时,它只是继续走出边界.我不明白必须做什么才能将它保持在边界内,即使在缩放时也是如此.请帮我一个代码来防止这种行为.如果您也可以附加演示,那就太棒了.
<html>
<head>
<title>Basic usage</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.3/fabric.min.js"></script>
</head>
<body>
<canvas id="canvas" style= "border: 1px solid black" height= 480 width = 360></canvas>
<script>
var canvas = new fabric.Canvas('canvas');
canvas.add(new fabric.Circle({ radius: 30, fill: '#f55', top: 100, left: 100 }));
canvas.item(0).set({
borderColor: 'gray',
cornerColor: 'black',
cornerSize: 12,
transparentCorners: true
});
canvas.setActiveObject(canvas.item(0));
canvas.renderAll();
canvas.on('object:moving', function (e) {
var obj = e.target;
// if object is too big ignore
if(obj.currentHeight > obj.canvas.height || obj.currentWidth > obj.canvas.width){
return;
}
obj.setCoords();
// top-left corner
if(obj.getBoundingRect().top < 0 || obj.getBoundingRect().left < 0){
obj.top = Math.max(obj.top, obj.top-obj.getBoundingRect().top);
obj.left = Math.max(obj.left, obj.left-obj.getBoundingRect().left);
}
// bot-right corner
if(obj.getBoundingRect().top+obj.getBoundingRect().height > obj.canvas.height || obj.getBoundingRect().left+obj.getBoundingRect().width > obj.canvas.width){
obj.top = Math.min(obj.top, obj.canvas.height-obj.getBoundingRect().height+obj.top-obj.getBoundingRect().top);
obj.left = Math.min(obj.left, obj.canvas.width-obj.getBoundingRect().width+obj.left-obj.getBoundingRect().left);
}
});
</script>
</body>
</html>
我的演示附在这里. :
https://jsfiddle.net/3v0cLaLk/
解决方法:
如果要执行实时防护,则应使用object:scaling事件作为object:modified仅在转换结束时触发.
1)向canvas添加事件处理程序:
this.canvas.on('object:scaling', (e) => this._handleScaling(e));
2)在处理函数中,获取旧对象和新对象的边界矩形:
_handleScaling(e) {
var obj = e.target;
var brOld = obj.getBoundingRect();
obj.setCoords();
var brNew = obj.getBoundingRect();
3)对于每个边框,检查对象是否已缩放超出画布边界并计算其left,top和scale属性:
// left border
// 1. compute the scale that sets obj.left equal 0
// 2. compute height if the same scale is applied to Y (we do not allow non-uniform scaling)
// 3. compute obj.top based on new height
if(brOld.left >= 0 && brNew.left < 0) {
let scale = (brOld.width + brOld.left) / obj.width;
let height = obj.height * scale;
let top = ((brNew.top - brOld.top) / (brNew.height - brOld.height) *
(height - brOld.height)) + brOld.top;
this._setScalingProperties(0, top, scale);
}
4)其他边界的类似代码:
// top border
if(brOld.top >= 0 && brNew.top < 0) {
let scale = (brOld.height + brOld.top) / obj.height;
let width = obj.width * scale;
let left = ((brNew.left - brOld.left) / (brNew.width - brOld.width) *
(width - brOld.width)) + brOld.left;
this._setScalingProperties(left, 0, scale);
}
// right border
if(brOld.left + brOld.width <= obj.canvas.width
&& brNew.left + brNew.width > obj.canvas.width) {
let scale = (obj.canvas.width - brOld.left) / obj.width;
let height = obj.height * scale;
let top = ((brNew.top - brOld.top) / (brNew.height - brOld.height) *
(height - brOld.height)) + brOld.top;
this._setScalingProperties(brNew.left, top, scale);
}
// bottom border
if(brOld.top + brOld.height <= obj.canvas.height
&& brNew.top + brNew.height > obj.canvas.height) {
let scale = (obj.canvas.height - brOld.top) / obj.height;
let width = obj.width * scale;
let left = ((brNew.left - brOld.left) / (brNew.width - brOld.width) *
(width - brOld.width)) + brOld.left;
this._setScalingProperties(left, brNew.top, scale);
}
5)如果对象的BoundingRect已跨越画布边界,请修复其位置和比例:
if(brNew.left < 0
|| brNew.top < 0
|| brNew.left + brNew.width > obj.canvas.width
|| brNew.top + brNew.height > obj.canvas.height) {
obj.left = this.scalingProperties['left'];
obj.top = this.scalingProperties['top'];
obj.scaleX = this.scalingProperties['scale'];
obj.scaleY = this.scalingProperties['scale'];
obj.setCoords();
} else {
this.scalingProperties = null;
}
}
6)最后,在设置缩放属性时,我们必须坚持使用最小的比例,以防对象跨越多个边框:
_setScalingProperties(left, top, scale) {
if(this.scalingProperties == null
|| this.scalingProperties['scale'] > scale) {
this.scalingProperties = {
'left': left,
'top': top,
'scale': scale
};
}
}