我有興趣想知道這個問題,因爲我也一直試圖將fabric.js對象與knockout模型集成 - 我想我很放心,沒有一個明顯的答案。下面是顯示我最新思想的示例: https://jsfiddle.net/whippet71/aky9af6t/ 它在DOM對象(文本框)和當前選定的畫布對象之間具有雙向數據綁定。
HTML:
<div>
<canvas id="mycanvas" width="600" height="400"></canvas>
</div>
<div class="form form-inline">
<div class="form-group">X: <input data-bind="textInput: x" class="form-control"></div>
<div class="form-group">Y: <input data-bind="textInput: y" class="form-control"></div>
</div>
的Javascript:
var jsonFromServer = [{"type":"rectangle","left":10,"top":100,"width":50,"height":50},{"type":"rectangle","left":85,"top":100,"width":50,"height":50},{"type":"circle","left":25,"top":250,"radius":50}];
var selectedObject;
var canvas = new fabric.Canvas('mycanvas');
for (var i=0; i<jsonFromServer.length; i++) {
var thisShape = jsonFromServer[i];
if (thisShape.type == 'rectangle') {
var rect = new fabric.Rect({
width: thisShape.width,
height: thisShape.height,
left: thisShape.left,
top: thisShape.top,
fill: 'blue'
});
canvas.add(rect);
} else if (thisShape.type == 'circle') {
var circle = new fabric.Circle({
radius: thisShape.radius,
left: thisShape.left,
top: thisShape.top,
fill: 'green'
});
canvas.add(circle);
}
}
// Set first object as selected by default
selectedObject = canvas.getObjects()[0];
canvas.setActiveObject(selectedObject);
// A view model to represent the currently selected canvas object
function ShapeViewModel(initX, initY) {
var self = this;
self.x = ko.observable(initX);
self.y = ko.observable(initY);
// Create a computed observable which we subsribe to, to notice change in x or y position
// Use deferred updates to avoid cyclic notifications
self.position = ko.computed(function() {
return { x: self.x(), y: self.y() };
}).extend({ deferred: true });
}
var vm = new ShapeViewModel(selectedObject.left, selectedObject.top);
ko.applyBindings(vm);
// Function to update the knockout observable
function updateObservable(x, y) {
vm.x(x);
vm.y(y);
}
// Fabric event handler to detect when user moves an object on the canvas
var myHandler = function (evt) {
selectedObject = evt.target;
updateObservable(selectedObject.get('left'), selectedObject.get('top'));
}
// Bind the event handler to the canvas
// This does mean it will be triggered by ANY object on the canvas
canvas.on({ 'object:selected': myHandler, 'object:modified': myHandler });
// Make a manual subscription to the computed observable so that we can
// update the canvas if the user types in new co-ordinates
vm.position.subscribe(function (newPos) {
console.log("new x=" + newPos.x + " new y=" + newPos.y);
selectedObject.setLeft(+newPos.x);
selectedObject.setTop(+newPos.y);
selectedObject.setCoords();
canvas.renderAll();
// Update server...
});
有幾件事情需要注意:
- 我創建了一個ko.observable並進行手動訂閱它爲目的更新織物對象
- 我設置了織物事件h更新關於對象選擇/修改的ko.observable。我沒有任何需要綁定到除當前選定對象之外的其他任何東西。
- 我不得不使用延遲更新,以避免循環更新(布更新KO,然後通知布...)
我很新的淘汰賽,因此任何的意見/建議將受到歡迎。
你介意分享一個提供雙向數據綁定的源代碼的小提琴或其他演示嗎?我可以在下面的答案中看到小提琴中的一種方式。另外,您是否遇到過面料和淘汰賽的其他問題? –
我們沒有繼續使用面料。我們開始使用基於svg(而不是canvas)的jointjs.com,這允許我們將html嵌入到圖表中並綁定到這些圖表。我不推薦這個確切的庫本身,但我猜想類似的東西會是一個愚蠢的選擇。這段時間以後快速創建小提琴有點難。 – bertvh
感謝您的分享。我正在用JointJS和knockoutjs創建一個PoC。你能分享一下嗎?我正在研究在jointjs元素中嵌入html。 –