我有兴趣遇到这个问题,因为我也一直在尝试将 fabric.js 对象与淘汰模型集成 - 我想我确信没有一个明显的答案。这是显示我最新想法的示例:
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 并手动订阅它以更新结构对象
- 我设置了一个结构事件处理程序,用于在对象选择/修改时更新 ko.observable。除了当前选定的对象之外,我不需要绑定任何东西。
- 我不得不使用延迟更新来避免循环更新(fabric updates ko,然后通知fabric...)
我对淘汰赛很陌生,所以欢迎任何 cmets/建议。