JavaScript
var r = Raphael("holder", window.innerWidth, window.innerHeight)
function findReflected(coord, about) {
var diff = about - coord;
return about + diff;
}
function curve(x1,y1, cx1,cy1, cx2,cy2, x2,y2, cx3,cy3, x3,y3, color) { //zx --x1
var cx2b = findReflected(cx2, x2),
cy2b = findReflected(cy2, y2),
path = [["M", x1, y1], ["C", cx1,cy1, cx2,cy2, x2,y2, "S", cx3,cy3, x3,y3]],
path2 = [["M", x1, y1], ["L", cx1, cy1],
["M", cx2, cy2], ["L", cx2b, cy2b],
["M", x3,y3],['L', cx3,cy3]],
curve = r.path(path).attr({stroke: color || Raphael.getColor(), "stroke-width": 4, "stroke-linecap": "round"}),
controls = r.set(
r.path(path2).attr({stroke: "#ccc", "stroke-dasharray": ". ","stroke-width":2}),
r.circle(x1, y1, 5).attr({fill: "red", stroke: "none"}),
r.circle(cx1, cy1, 5).attr({fill: "green", stroke: "none"}),
r.circle(cx2, cy2, 5).attr({fill: "blue", stroke: "none"}),
r.circle(x2, y2, 5).attr({fill: "yellow", stroke: "none"}),
r.circle(cx2b, cy2b, 5).attr({fill: "pink", stroke: "none"}),
r.circle(cx3, cy3, 5).attr({fill: "grey", stroke: "none"}),
r.circle(x3, y3, 5).attr({fill: "brown", stroke: "none"})
);
controls[1].update = function (x, y) {
var X = this.attr("cx") + x,
Y = this.attr("cy") + y;
this.attr({cx: X, cy: Y});
path[0][1] = X;
path[0][2] = Y;
path2[0][1] = X;
path2[0][2] = Y;
controls[2].update(x, y);
};
controls[2].update = function (x, y) {
var X = this.attr("cx") + x,
Y = this.attr("cy") + y;
this.attr({cx: X, cy: Y});
path[1][1] = X;
path[1][2] = Y;
path2[1][1] = X;
path2[1][2] = Y;
curve.attr({path: path});
controls[0].attr({path: path2});
};
controls[3].update = function (x, y, doReflect) {
...