2017-01-16 81 views
0

版本創建通過鼠標拖拽多邊形的形狀並不中心到其選區邊界框

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功能,我發現它的地方,在網絡上,而前,不幸的是,我不能再次找到它的鏈接,貸記本神奇功能的創造者。

回答

2

當你有一個小提琴是非常好的和快速的轉換它在一個工作片段,因爲然後得到一個答案是非常容易的。

說的那麼重要的一點是,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, { 
 
\t backgroundColor: '#fff', 
 
\t width: 600, 
 
\t height: 600 
 
}); 
 
canvas.renderAll(); 
 

 
drawPoly.addEventListener('click', (e)=>{ 
 
\t canvas.defaultCursor = "crosshair"; 
 
\t canvas.selection = false; 
 
\t canvas.discardActiveObject(); 
 
\t canvas.discardActiveGroup(); 
 
\t canvas.forEachObject(object=>{ object.selectable = false; }); 
 
\t canvas.renderAll(); 
 

 
\t canvas.on('mouse:down', opt => { 
 
\t \t 
 
\t \t if (canvas.selection) return; 
 
\t \t var pointer = canvas.getPointer(opt.e) 
 

 
\t \t origX = pointer.x; 
 
\t \t origY = pointer.y; 
 

 
\t \t // I have also tried initial calculations here 
 
\t \t // by using calcPolygonPoints(8, Math.abs(origX - pointer.x)/2) instead of [] 
 
\t \t // The result is the same 
 
\t \t const polygon = new fabric.Polygon(calcPolygonPoints(8, Math.abs(origX - pointer.x)/2), { 
 
\t \t \t objectCaching: false, 
 
\t \t \t left: origX, 
 
\t \t \t top: origY, 
 
\t \t \t originX: 'center', 
 
\t \t \t originY: 'center', 
 
\t \t \t fill: 'rgba(255,255,255, 1)', 
 
\t \t \t perPixelTargetFind: false, 
 
\t \t \t strokeWidth: 1, 
 
\t \t \t strokeDashArray: [0,0], 
 
\t \t \t objType: 'shape', 
 
\t \t \t stroke: 'rgba(17,17,17,1)', 
 
\t \t \t hasControls: false, 
 
\t \t \t hasBorders: false 
 
\t \t }) 
 
\t \t // polygon._calcDimensions() 
 
\t \t canvas.add(polygon).setActiveObject(polygon) 
 

 
\t }).on('mouse:move', opt => { 
 

 
\t \t if (canvas.selection || !canvas.getActiveObject()) return; 
 
\t \t const newShape = canvas.getActiveObject() 
 
\t \t var pointer = canvas.getPointer(opt.e) 
 

 
\t \t if (newShape) { 
 
\t \t \t newShape.set({ 
 
\t \t \t \t points: calcPolygonPoints(8, Math.abs(origX - pointer.x)/2) 
 
\t \t \t }) 
 
\t \t \t newShape._calcDimensions() 
 
\t \t } 
 
\t \t changeSize.value = Math.abs(origX - pointer.x)/2; 
 
\t \t canvas.renderAll() 
 

 
\t }).on('mouse:up', opt => { 
 
\t \t // In my app I am using redux stores to turn off the drawing 
 
\t \t // Here I used the following if statement to turn off the drawing 
 
\t \t if (canvas.selection) return; 
 

 
\t \t const newShape = canvas.getActiveObject() 
 
\t \t if (newShape) { 
 
\t \t \t newShape.set({ 
 
\t \t \t \t hasControls: true, 
 
\t \t \t \t hasBorders: true 
 
\t \t \t }) 
 
     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') 
 
\t \t \t newShape.setCoords() 
 
\t \t \t canvas.renderAll() 
 
\t \t } 
 
\t \t canvas.renderAll() 
 
\t \t canvas.selection = true; 
 

 
\t \t canvas.off('mouse:down').off('mouse:move') 
 
\t \t canvas.defaultCursor = "default"; 
 
\t \t canvas.discardActiveObject() 
 
\t \t canvas.forEachObject(object=>{ 
 
\t \t \t if (object.evented) object.selectable = true; 
 
\t \t }) 
 
\t }) 
 
}) 
 

 
changeSize.addEventListener('input', (e)=>{ 
 
\t if (!canvas.getActiveObject()) return; 
 
\t 
 
\t canvas.getActiveObject().set({ 
 
\t \t points: calcPolygonPoints(8, parseInt(e.target.value, 10)) 
 
\t }) 
 
\t canvas.getActiveObject()._calcDimensions() 
 
\t canvas.renderAll() 
 
})
button { 
 
\t border: 0 none; 
 
\t background: #2ecc70; 
 
\t border-radius: 5px; 
 
\t cursor: pointer; 
 
\t color: #fff; 
 
\t box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08); 
 
\t text-transform: uppercase; 
 
\t padding: 11px 22px; 
 
\t font-weight: 600; 
 
\t font-size: 13px; 
 
\t letter-spacing: 1px; 
 
\t margin: 10px auto; 
 
\t outline: 0 none; 
 
} 
 

 
input { 
 
\t border: 1px solid #ddd; 
 
\t box-shadow: none; 
 
\t padding: 11px; 
 
\t font-size: 13px; 
 
\t border-radius: 5px; 
 
\t margin-left: 10px; 
 
\t max-width: 50px; 
 
\t outline: 0 none !important; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.3/fabric.min.js"></script> 
 
<div id="wrapper"> 
 
\t <canvas id="my-canvas"></canvas> 
 
\t <button id="draw-poly">Draw Polygon</button> 
 
\t <input type="number" id="change-size" value="0" /> 
 
</div>

+0

非常感謝您@AndreaBogazzi,現在它的工作原理。我把'''newShape。鼠標移動事件中的pathOffset'''以避免創建形狀時的跳躍。另外,這是否意味着如果我決定改變形狀的大小(不縮放),我還必須在那裏運行'''newShape.pathOffset''呢? –