This has been done already at Demonstration project. You can download notebook with the source code at the link below, but I also give it here - it is not that big.
Spline Sketchpad, by Yu-Sung Chang
Manipulate[
If[(prevdegree =!= degree) || (prevapprox =!= approx),
degree = If[approx < 20, Min[degree, 2], degree];
ctrlpts =
Table[splineFit[p,
Max[{Floor[(1 - approx/100) Length[p]], degree + 1}],
degree], {p, pts}]; prevdegree = degree; prevapprox = approx];
EventHandler[
Graphics[{
CapForm["Round"], JoinForm["Round"],
If[ctrlpts =!= {},
MapThread[{#1, Opacity[#2], AbsoluteThickness[#3],
BSplineCurve[#4, SplineDegree -> degree]} &, {colorlist,
opacitylist, thicknesslist, ctrlpts}], {}],
If[down && pts =!= {}, {color, Opacity[opacity],
AbsolutePointSize[thickness], Point[Last[pts]]}, {}],
If[pen && pts =!= {},
If[down, Point /@ Most[pts], Point /@ pts], {}]
},
PlotRange -> 1, ImageSize -> 400, AspectRatio -> 1/GoldenRatio,
Frame -> True, FrameTicks -> False],
{"MouseDown" :> (AppendTo[pts, {MousePosition["Graphics"]}];
down = True),
"MouseMoved" :> (If[down,
AppendTo[pts[[count]], MousePosition["Graphics"]]]),
"MouseUp" :> (down = False; count++;
ctrlpts =
Table[splineFit[p,
Max[{Floor[(1 - approx/100) Length[p]], degree + 1}],
degree], {p, pts}]; AppendTo[colorlist, color];
AppendTo[opacitylist, opacity];
AppendTo[thicknesslist, thickness])}
],
(* Pen controls *)
Row[{Control[{color, Blue}],
Control[{{pen, False, "show points"}, {True, False}}]}, Spacer[10]],
{{thickness, 4}, 1, 20, Appearance -> "Labeled", ImageSize -> Medium},
{{opacity, 1}, 0, 1, Appearance -> "Labeled", ImageSize -> Medium},
Delimiter,
(* Spline controls *)
Row[{Control[{{approx, 30, "approximation"}, 0, 100, 1,
ImageSize -> Small}], Spacer[10], Dynamic[approx], "%"}],
Row[{Control[{{degree, 2,
"spline degree"}, (Dynamic[
If[approx < 20, RadioButtonBar[Dynamic[degree], {1, 2}],
RadioButtonBar[Dynamic[degree], {1, 2, 3, 4}]]] &)}],
Control[{{dummy, "", ""},
Button["clear",
colorlist = opacitylist = thicknesslist = pts = ctrlpts = {};
down = False; count = 1, ImageSize -> 50] &}]}],
(* Dummies *)
{{colorlist, {}}, ControlType -> None},
{{thicknesslist, {}}, ControlType -> None},
{{opacitylist, {}}, ControlType -> None},
{{prevapprox, 0}, ControlType -> None},
{{prevdegree, 2}, ControlType -> None},
{{pts, {}}, ControlType -> None},
{{ctrlpts, {}}, ControlType -> None},
{{down, False}, ControlType -> None},
{{count, 1}, ControlType -> None},
AutorunSequencing -> {2, 5},
Initialization :> (
splineFit[pts_, n_, d_] := Module[{uparam, knots, basis},
If[Length[pts] == 1, Return[Join[pts, pts]]];
If[Length[pts] <= d, Return[pts]];
(*uparam=With[{acc=N[Accumulate[Norm/@pts]]},(acc-First[
acc])/(Last[acc]-First[acc])];*)
uparam = N[Range[0, 1, 1/(Length[pts] - 1)]];
knots =
Join[ConstantArray[0, d], Range[0, 1, 1/(n - d)],
ConstantArray[1, d]];
basis =
Table[BSplineBasis[{d, knots}, j - 1, uparam[[i]]], {i,
Length[uparam]}, {j, n}];
LeastSquares[basis, pts]];
)
]