通过鼠标拖动创建多边形形状不会将形状居中到其选择边框框
Creating polygon shapes via mouse drag does not center the shape to its selection border box
版本
1.7.3
测试用例
https://jsfiddle.net/human_a/twdgya93/
在这个 fiddle 中,我也尝试使用以下代码创建形状以避免创建空多边形,但结果是一样的:
const polygon = new fabric.Polygon(calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 ), {
objectCaching: false,
left: origX,
top: origY,
originX: 'center',
originY: 'center',
fill: 'rgba(255,255,255, 1)',
perPixelTargetFind: false,
strokeWidth: 1,
strokeDashArray: [0,0],
objType: 'shape',
stroke: 'rgba(17,17,17,1)',
hasControls: false,
hasBorders: false
})
重现步骤
单击绿色按钮进入绘图模式,将鼠标拖入 canvas 开始创建形状,松开鼠标,然后尝试选择新创建的形状。边界框大小与新多边形的大小匹配,但定位不正确。
预期行为
如果我尝试创建任何其他类型的形状(矩形、圆形或三角形)而不是多边形,它会完美地工作。
实际行为
由于多边形使用不同的方法通过计算点来计算宽度和高度,并且由于在这种创建形状的方法中,width/height 是在创建形状后计算的(mouse:move 事件)边界矩形将无法正确定位。
此外,即使我尝试更改多边形的大小(我不想缩放形状,这是个坏主意)再次边界矩形定位不正确,您可以在上面的演示中尝试使用按钮旁边的数字输入字段。
PS
我没有写 calcPolygonPoints 函数,我前段时间在网上找到它,不幸的是,我找不到它 link 再次感谢这个神奇函数的创建者。
当你有一个 fiddle 时,将它转换成一个工作片段非常好而且很快,从那以后得到答案就很容易了。
这么说,重点是fabric.js中的多边形不支持点更新。您已经在调用 _calcDimensions()
但这还不够。
要使多边形在边界框中正确居中,您还必须使用更新后的值填充其 pathOffset 属性。
我在 mouseUp 事件的片段中添加了这个。
var canvas = new fabric.Canvas();
var el = document.getElementById('my-canvas');
var drawPoly = document.getElementById('draw-poly');
var changeSize = document.getElementById('change-size');
var origX, origY;
var calcPolygonPoints = (sideCount,radius) => {
var sweep=Math.PI*2/sideCount;
var cx=radius;
var cy=radius;
var points=[]
for(var i=0;i<sideCount;i++){
var x=cx+radius*Math.cos( i*sweep )
var y=cy+radius*Math.sin( i*sweep )
points.push( { x:x, y:y } )
}
return(points)
}
canvas.initialize(el, {
backgroundColor: '#fff',
width: 600,
height: 600
});
canvas.renderAll();
drawPoly.addEventListener('click', (e)=>{
canvas.defaultCursor = "crosshair";
canvas.selection = false;
canvas.discardActiveObject();
canvas.discardActiveGroup();
canvas.forEachObject(object=>{ object.selectable = false; });
canvas.renderAll();
canvas.on('mouse:down', opt => {
if (canvas.selection) return;
var pointer = canvas.getPointer(opt.e)
origX = pointer.x;
origY = pointer.y;
// I have also tried initial calculations here
// by using calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 ) instead of []
// The result is the same
const polygon = new fabric.Polygon(calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 ), {
objectCaching: false,
left: origX,
top: origY,
originX: 'center',
originY: 'center',
fill: 'rgba(255,255,255, 1)',
perPixelTargetFind: false,
strokeWidth: 1,
strokeDashArray: [0,0],
objType: 'shape',
stroke: 'rgba(17,17,17,1)',
hasControls: false,
hasBorders: false
})
// polygon._calcDimensions()
canvas.add(polygon).setActiveObject(polygon)
}).on('mouse:move', opt => {
if (canvas.selection || !canvas.getActiveObject()) return;
const newShape = canvas.getActiveObject()
var pointer = canvas.getPointer(opt.e)
if (newShape) {
newShape.set({
points: calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 )
})
newShape._calcDimensions()
}
changeSize.value = Math.abs( origX - pointer.x ) / 2;
canvas.renderAll()
}).on('mouse:up', opt => {
// In my app I am using redux stores to turn off the drawing
// Here I used the following if statement to turn off the drawing
if (canvas.selection) return;
const newShape = canvas.getActiveObject()
if (newShape) {
newShape.set({
hasControls: true,
hasBorders: true
})
newShape.pathOffset = {
x: newShape.minX + newShape.width / 2,
y: newShape.minY + newShape.height / 2
};
var pointer = canvas.getPointer(opt.e);
var center = { x: (pointer.x + origX)/2, y: (pointer.y + origY)/2}
newShape.setPositionByOrigin(center, 'center', 'center')
newShape.setCoords()
canvas.renderAll()
}
canvas.renderAll()
canvas.selection = true;
canvas.off('mouse:down').off('mouse:move')
canvas.defaultCursor = "default";
canvas.discardActiveObject()
canvas.forEachObject(object=>{
if (object.evented) object.selectable = true;
})
})
})
changeSize.addEventListener('input', (e)=>{
if (!canvas.getActiveObject()) return;
canvas.getActiveObject().set({
points: calcPolygonPoints(8, parseInt(e.target.value, 10) )
})
canvas.getActiveObject()._calcDimensions()
canvas.renderAll()
})
button {
border: 0 none;
background: #2ecc70;
border-radius: 5px;
cursor: pointer;
color: #fff;
box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
text-transform: uppercase;
padding: 11px 22px;
font-weight: 600;
font-size: 13px;
letter-spacing: 1px;
margin: 10px auto;
outline: 0 none;
}
input {
border: 1px solid #ddd;
box-shadow: none;
padding: 11px;
font-size: 13px;
border-radius: 5px;
margin-left: 10px;
max-width: 50px;
outline: 0 none !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.3/fabric.min.js"></script>
<div id="wrapper">
<canvas id="my-canvas"></canvas>
<button id="draw-poly">Draw Polygon</button>
<input type="number" id="change-size" value="0" />
</div>
版本
1.7.3
测试用例
https://jsfiddle.net/human_a/twdgya93/
在这个 fiddle 中,我也尝试使用以下代码创建形状以避免创建空多边形,但结果是一样的:
const polygon = new fabric.Polygon(calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 ), {
objectCaching: false,
left: origX,
top: origY,
originX: 'center',
originY: 'center',
fill: 'rgba(255,255,255, 1)',
perPixelTargetFind: false,
strokeWidth: 1,
strokeDashArray: [0,0],
objType: 'shape',
stroke: 'rgba(17,17,17,1)',
hasControls: false,
hasBorders: false
})
重现步骤
单击绿色按钮进入绘图模式,将鼠标拖入 canvas 开始创建形状,松开鼠标,然后尝试选择新创建的形状。边界框大小与新多边形的大小匹配,但定位不正确。
预期行为
如果我尝试创建任何其他类型的形状(矩形、圆形或三角形)而不是多边形,它会完美地工作。
实际行为
由于多边形使用不同的方法通过计算点来计算宽度和高度,并且由于在这种创建形状的方法中,width/height 是在创建形状后计算的(mouse:move 事件)边界矩形将无法正确定位。
此外,即使我尝试更改多边形的大小(我不想缩放形状,这是个坏主意)再次边界矩形定位不正确,您可以在上面的演示中尝试使用按钮旁边的数字输入字段。
PS
我没有写 calcPolygonPoints 函数,我前段时间在网上找到它,不幸的是,我找不到它 link 再次感谢这个神奇函数的创建者。
当你有一个 fiddle 时,将它转换成一个工作片段非常好而且很快,从那以后得到答案就很容易了。
这么说,重点是fabric.js中的多边形不支持点更新。您已经在调用 _calcDimensions()
但这还不够。
要使多边形在边界框中正确居中,您还必须使用更新后的值填充其 pathOffset 属性。
我在 mouseUp 事件的片段中添加了这个。
var canvas = new fabric.Canvas();
var el = document.getElementById('my-canvas');
var drawPoly = document.getElementById('draw-poly');
var changeSize = document.getElementById('change-size');
var origX, origY;
var calcPolygonPoints = (sideCount,radius) => {
var sweep=Math.PI*2/sideCount;
var cx=radius;
var cy=radius;
var points=[]
for(var i=0;i<sideCount;i++){
var x=cx+radius*Math.cos( i*sweep )
var y=cy+radius*Math.sin( i*sweep )
points.push( { x:x, y:y } )
}
return(points)
}
canvas.initialize(el, {
backgroundColor: '#fff',
width: 600,
height: 600
});
canvas.renderAll();
drawPoly.addEventListener('click', (e)=>{
canvas.defaultCursor = "crosshair";
canvas.selection = false;
canvas.discardActiveObject();
canvas.discardActiveGroup();
canvas.forEachObject(object=>{ object.selectable = false; });
canvas.renderAll();
canvas.on('mouse:down', opt => {
if (canvas.selection) return;
var pointer = canvas.getPointer(opt.e)
origX = pointer.x;
origY = pointer.y;
// I have also tried initial calculations here
// by using calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 ) instead of []
// The result is the same
const polygon = new fabric.Polygon(calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 ), {
objectCaching: false,
left: origX,
top: origY,
originX: 'center',
originY: 'center',
fill: 'rgba(255,255,255, 1)',
perPixelTargetFind: false,
strokeWidth: 1,
strokeDashArray: [0,0],
objType: 'shape',
stroke: 'rgba(17,17,17,1)',
hasControls: false,
hasBorders: false
})
// polygon._calcDimensions()
canvas.add(polygon).setActiveObject(polygon)
}).on('mouse:move', opt => {
if (canvas.selection || !canvas.getActiveObject()) return;
const newShape = canvas.getActiveObject()
var pointer = canvas.getPointer(opt.e)
if (newShape) {
newShape.set({
points: calcPolygonPoints(8, Math.abs( origX - pointer.x ) / 2 )
})
newShape._calcDimensions()
}
changeSize.value = Math.abs( origX - pointer.x ) / 2;
canvas.renderAll()
}).on('mouse:up', opt => {
// In my app I am using redux stores to turn off the drawing
// Here I used the following if statement to turn off the drawing
if (canvas.selection) return;
const newShape = canvas.getActiveObject()
if (newShape) {
newShape.set({
hasControls: true,
hasBorders: true
})
newShape.pathOffset = {
x: newShape.minX + newShape.width / 2,
y: newShape.minY + newShape.height / 2
};
var pointer = canvas.getPointer(opt.e);
var center = { x: (pointer.x + origX)/2, y: (pointer.y + origY)/2}
newShape.setPositionByOrigin(center, 'center', 'center')
newShape.setCoords()
canvas.renderAll()
}
canvas.renderAll()
canvas.selection = true;
canvas.off('mouse:down').off('mouse:move')
canvas.defaultCursor = "default";
canvas.discardActiveObject()
canvas.forEachObject(object=>{
if (object.evented) object.selectable = true;
})
})
})
changeSize.addEventListener('input', (e)=>{
if (!canvas.getActiveObject()) return;
canvas.getActiveObject().set({
points: calcPolygonPoints(8, parseInt(e.target.value, 10) )
})
canvas.getActiveObject()._calcDimensions()
canvas.renderAll()
})
button {
border: 0 none;
background: #2ecc70;
border-radius: 5px;
cursor: pointer;
color: #fff;
box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08);
text-transform: uppercase;
padding: 11px 22px;
font-weight: 600;
font-size: 13px;
letter-spacing: 1px;
margin: 10px auto;
outline: 0 none;
}
input {
border: 1px solid #ddd;
box-shadow: none;
padding: 11px;
font-size: 13px;
border-radius: 5px;
margin-left: 10px;
max-width: 50px;
outline: 0 none !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.3/fabric.min.js"></script>
<div id="wrapper">
<canvas id="my-canvas"></canvas>
<button id="draw-poly">Draw Polygon</button>
<input type="number" id="change-size" value="0" />
</div>