版本
1.7.3
测试用例
https://jsfiddle.net/human_a/twdgya93/
在这个小提琴中,我也尝试使用以下代码创建形状以避免创建空多边形,但结果是相同的:
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
})
重现的步骤
单击绿色按钮进入绘图模式,在画布内拖动鼠标以开始创建形状,松开鼠标,然后尝试选择新创建的形状。边界框大小与新多边形的大小相匹配,但它没有正确定位。
预期行为
如果不使用多边形,我会尝试创建任何其他类型的形状(矩形,圆形或三角形)。它的工作非常精细。
实际行为
由于多边形通过计算点使用不同的方法来计算宽度和高度,因为在这种创建形状的方法中,宽度/高度是在创建形状(使用鼠标:移动事件)后计算的。矩形将无法正确定位。
即使我尝试更改多边形的大小(我不想缩放形状,这也是一个坏主意),边界矩形的位置也不正确,你可以尝试一下上面的演示使用按钮旁边的数字输入字段。
PS
我没有编写calcPolygonPoints函数,我不久前在网上找到了它,不幸的是,我再也找不到它的链接来归功于这个神奇功能的创造者。
答案 0 :(得分:3)
当你有一个小提琴是非常好的和快速的转换它在一个工作片段,因为那时得到答案很容易。
这么说,关键是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>