Interactive Cubic Bezier Demo

I wanted to make sure that I could still make custom Javascript demos in my new blogging platform (Squarespace, which I like a lot as of now). So I made a little cubic bezier demo to test it out. Easy as Math.PI

var CubicBezier = function(canvas, opts){
if(!opts) opts = {};

this.start = opts.start || new Vec2(100,100);
this.end = opts.end || new Vec2(400, 400);

this.c1 = opts.c1 || new Vec2(100, 300);
this.c2 = opts.c2 || new Vec2(300, 100);

this.listeners = [];
this.curve = new fabric.Path( this.toSVGPath() );

this.controlCurve = new fabric.Path( this.toControlPath() );

this.curve.selectable = this.controlCurve.selectable = false;
this.curve.fill = this.controlCurve.fill = 'none'
this.curve.stroke = 'black';

this.controlCurve.stroke = 'blue';
this.controlCurve.strokeDashArray = [5, 5];

canvas.add( this.curve, this.controlCurve );
canvas.renderAll();

this.renderControlPoints( canvas );

}

CubicBezier.prototype = {

toSVGPath : function(){
var str = "M"+this.start.toString();
str += "C"+this.c1.toString();
str += this.c2.toString();
str += this.end.toString();

return str
},

toControlPath : function(){
var str = "M"+this.start.toString();
str += "L"+this.c1.toString();
str += "L"+this.c2.toString();
str += "L"+this.end.toString();

return str
},

renderControlPoints : function(canvas){
var scope = this;

var r = 10;
var points = [
new fabric.Circle({ top: this.start.y, left: this.start.x,radius:r, as : 'start' }),
new fabric.Circle({ top: this.end.y, left: this.end.x, radius:r, as : 'end' }),
new fabric.Circle({ top: this.c1.y, left: this.c1.x, radius:r, as : 'c1' }),
new fabric.Circle({ top: this.c2.y, left: this.c2.x, radius:r, as : 'c2' })
];

points.forEach( function(p){
p.fill = '#f55';
p.stroke = "#2B436E"
p.hasControls = p.hasBorder = false;
p.perPixelTargetFind = true;
p.belongsTo = scope;
canvas.add(p);
})
},

renderCurve : function(canvas){
var dummyPath = new fabric.Path( this.toSVGPath() );
this.curve.path = dummyPath.path;

var dummyPath2 = new fabric.Path( this.toControlPath() );
this.controlCurve.path = dummyPath2.path;

canvas.renderAll();
}

}

// simple 2D vector class, for completeness and readability
var Vec2 = function(x, y){
this.x = x;
this.y = y;
}

Vec2.prototype = {
toString : function(){
return this.x+","+this.y+" "
}
}

// run it!
var canvas = new fabric.Canvas('c');
canvas.selection = false; // disable groups

var bezier = new CubicBezier(canvas);

// tie together the dragging with the bezier object
canvas.on('object:moving', function(e){
var obj = e.target;
if( obj.belongsTo ){
obj.belongsTo[ obj.as ].x = obj.left;
obj.belongsTo[ obj.as ].y = obj.top;
obj.belongsTo.renderCurve( canvas );
}
})