JSFiddle - React, Tailwind, and code Playground

by rniemeyer

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js"></script>
<script src="http://knockoutjs.com/downloads/knockout-3.1.0.debug.js"></script>
<div style="float: left" data-bind="with: rect">
    <div>
        <input data-bind="value: left" />Left</div>
    <div>
        <input data-bind="value: top" />Top</div>
    <div>
        <input data-bind="value: fill" />Fill</div>
    <div>
        <input data-bind="value: width" />Width</div>
    <div>
        <input data-bind="value: height" />Height</div>
</div>
<div data-bind="with: rect2">
    <div>
        <input data-bind="value: left" />Left</div>
    <div>
        <input data-bind="value: top" />Top</div>
    <div>
        <input data-bind="value: fill" />Fill</div>
    <div>
        <input data-bind="value: width" />Width</div>
    <div>
        <input data-bind="value: height" />Height</div>
</div>
<hr/>
<canvas id="c" data-bind="fabric: [ { type: 'Rect', params: rect.getParams }, { type: 'Rect', params: rect2.getParams } ]"></canvas>

JavaScript

ko.bindingHandlers.fabric = {
    init: function (element, valueAccessor) {
        var shapes = valueAccessor(),
            canvas = new fabric.Canvas(element);

        ko.utils.arrayForEach(shapes, function (shape) {
            //create the new shape and initialize it
            var newShape = new fabric[shape.type](shape.params());
            canvas.add(newShape);

            //track changes to the shape (dependencies accessed in the params() function
            ko.computed(function () {
                newShape.set(this.params());
                canvas.renderAll();
            }, shape, {
                disposeWhenNodeIsRemoved: element
            });

        });
    }
};

var RectangleViewModel = function (left, top, fill, width, height) {
    this.left = ko.observable(left);
    this.top = ko.observable(top);
    this.fill = ko.observable(fill);
    this.width = ko.observable(width);
    this.height = ko.observable(height);

    this.getParams = function () {
        return {
            left: +this.left(),
            top: +this.top(),
            fill: this.fill(),
            width: +this.width(),
            height: +this.height()
        };
    }.bind(this);

};

var vm = {
    rect: new RectangleViewModel(100, 100, "red", 100, 100),
    rect2: new RectangleViewModel(50, 50, "blue", 50, 50)
};

ko.applyBindings(vm);