Edit in JSFiddle

function init() {
    canvas = document.getElementById('canvas');
    width = canvas.clientWidth;
    height = canvas.clientHeight;
    canvas.width = width;
    canvas.height = height;
    ctx = canvas.getContext('2d');
    controlLock = false;

    rotX = 0;
    rotY = 0;
    rotZ = 0;
    animate = 0;

    document.controls = {};
    var knobElements = document.getElementsByClassName("knob");
    for (var i = 0; i < knobElements.length; i++) {
        knobInit(knobElements[i]);
    }
    document.body.onmousemove = bodyOnMouseMove;
    document.body.onmouseup = bodyOnMouseUp;

    setInterval("render()", 50);

    //    calculate();render();
}

function calculate() {
    with(Math) {
        for (id in document.controls) {
            var ctrl = document.controls[id];
            ctrl.lfoPhase += 10 * ctrl.lfoRate;

            switch (ctrl.lfoType) {
            case 'sin':
                ctrl.lfoValue = sin(2 * PI * ctrl.lfoPhase);
                break;
            case 'up':
                ctrl.lfoValue = (ctrl.lfoPhase % 1.0);
                break;
            case 'down':
                ctrl.lfoValue = -(ctrl.lfoPhase % 1.0);
                break;
            case 'rnd':
                if (ctrl.lfoPhase >= 1) {
                    ctrl.lfoValue = 2 * random() - 1;
                    ctrl.lfoPhase = ctrl.lfoPhase % 1.0;
                }
                break;
            default:
                break;
            }

            var value = ctrl.knobValue + ctrl.lfoAmount * ctrl.lfoValue;

            eval(id + " = " + value);
        }
    }
}

function render() {
    calculate();
    with(Math) {
        rotX = rotX + 0.1 * (-0.5 + rotateX);
        rotY = rotY + 0.1 * (-0.5 + rotateY);
        rotZ = rotZ + 0.1 * (-0.5 + rotateZ);
        animate = animate + anim * 30;
        sp_t = max(sp_t, 0.01);
        sp_T = max(sp_T, 0.001);
        sp_T2 = max(sp_T2, 0.01);
        sp_k = max(sp_k, 0.000001);

        ctx.globalAlpha = pow(bgAlpha, 3);
        ctx.fillStyle = 'rgb(' + floor(bgRed * 255) + ',' + floor(bgGreen * 255) + ',' + floor(bgBlue * 255) + ')';
        ctx.fillRect(0, 0, width, height);

        ctx.globalAlpha = alpha;

        ctx.strokeStyle = 'rgb(' + floor(red * 255) + ',' + floor(green * 255) + ',' + floor(blue * 255) + ')';
        ctx.lineWidth = max(pow(lineWidth, 7) * 200, 0.1);



        ctx.beginPath();
        var s = max(sp_t * sp_k, 0.001);
        var count = (2 * sp_T / s) * sp_T2 * 100;
        var xx = 0;
        var yy = 0;
        var xxx = 0;
        var yyy = 0;
        var multicolormode = (zScale > 0) ? true : false;
        var scale = height;

        for (var i = -2; i <= count + 1; i++) {
            var t = (animate + i) * PI * s;

            var xo = (1 - sp_k) * cos(t) + (-2 + 4 * sp_l) * sp_k * cos(t * (1 - sp_k) / sp_k);
            var yo = (1 - sp_k) * sin(t) - (-2 + 4 * sp_l) * sp_k * sin(t * (1 - sp_k) / sp_k);
            var zo = 0;
            var rx = rotX + t * x3D;
            var ry = rotY + t * y3D;
            var rz = rotZ;
            var x = xo * (cos(ry) * cos(rz)) + yo * (-cos(rx) * sin(rz) + sin(rx) * sin(ry) * cos(rz)) + zo * (sin(rx) * sin(rz) + cos(rx) * sin(ry) * cos(rz));
            var y = xo * (cos(ry) * sin(rz)) + yo * (cos(rx) * cos(rz) + sin(rx) * sin(ry) * sin(rz)) + zo * (-sin(rx) * cos(rz) + cos(rx) * sin(ry) * sin(rz));
            var z = xo * (-sin(ry)) + yo * (sin(rx) * cos(ry)) + zo * (cos(rx) * cos(ry));

            //var x = xo*cos(rz) - yo*sin(rz);
            //var y = xo*sin(rz) + yo*cos(rz);
            x = scale * sp_R * x + (posX * width);
            y = scale * sp_R * y + (posY * height);
            if (i <= 0) {
                ctx.moveTo(x, y);
            }
            else {
                if (multicolormode) {
                    ctx.beginPath();

                    var cz = max(min((z + 2 * zOffset - 1) * 2 * zScale, 1), -1);
                    var cr = floor(255 * (z < 0 ? bgRed + (1 + cz) * (red - bgRed) : red + cz * (1 - red)));
                    var cg = floor(255 * (z < 0 ? bgGreen + (1 + cz) * (green - bgGreen) : green + cz * (1 - green)));
                    var cb = floor(255 * (z < 0 ? bgBlue + (1 + cz) * (blue - bgBlue) : blue + cz * (1 - blue)));
                    ctx.strokeStyle = 'rgb(' + cr + ',' + cg + ',' + cb + ')';
                    ctx.moveTo(xxx, yyy);
                    ctx.lineTo(xx, yy);
                    ctx.lineTo(x, y);
                    ctx.stroke();
                }
                else {
                    ctx.lineTo(x, y);
                }
            }
            xxx = xx;
            yyy = yy;
            xx = x;
            yy = y;
        }
        ctx.stroke();
    }
    controlLock = false;
}

function bodyOnMouseMove(event) {
    if (!controlLock && document.dragElement) {
        controlLock = true;
        document.dragElement.ondrag(event);
    }
}

function bodyOnMouseUp(event) {
    if (document.dragElement) {
        document.dragElement = null;
    }
}

function eGetElement(event) {
    if (window.event) // IE
    return event.srcElement;
    else if (event.target) // Netscape/Firefox/Opera
    return event.target;
    return null;
}

function eGetX(event) {
    var nRet = 0;
    var evt = event ? event : window.event;
    if (evt.pageX) nRet = evt.pageX;
    else if (evt.clientX) nRet = evt.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
    return nRet;
}

function eGetY(event) {
    var nRet = 0;
    var evt = event ? event : window.event;
    if (evt.pageY) nRet = evt.pageY;
    else if (evt.clientY) nRet = evt.clientY + document.body.scrollTop + document.documentElement.scrollTop;
    return nRet;
}


function knobInit(element) {
    if (!element.id) {
        var id = "";
        do {
            id = "knob" + Math.round(Math.random() * 10000, 0);
        }
        while (document.getElementById(id) != null);
        element.id = id;
    }

    var lfoTypes = "<option>sin</option><option>up</option><option>down</option><option>rnd</option>";
    var initValue = Math.min(Math.max(Number(element.innerHTML), 0), 1);

    document.controls[element.id] = {
        knobValue: initValue,
        knobMinValue: 0,
        knobMaxValue: 0,
        lfoType: "sin",
        lfoRate: 0,
        lfoAmount: 0,
        lfoPhase: 0,
        lfoValue: 0
    };

    element.innerHTML = "<div class='knob_label'>" + element.title + "</div>"


    + "<div class='knob_body' id='" + element.id + "_body'>" + "<div class='knob_knob' id='" + element.id + "_knob'>" + "<div class='knob_arrow'>&nbsp;</div></div></div>"

    + "<input class='knob_min_input' id='" + element.id + "_min_input' value='0'>" + "<input class='knob_max_input' id='" + element.id + "_max_input' value='1'>" + "<input class='knob_input' id='" + element.id + "_input'>"

    + "<div class='knob_lfo_type' id='" + element.id + "_lfo_type'>LFO: sin</div>" + "<select class='knob_lfo_type_select' onchange='knobOnLfoChange(this)' id='" + element.id + "_lfo_type_select'>" + lfoTypes + "</select>"

    + "<div class='knob_lfo' id='" + element.id + "_rate' title='Rate' style='margin-right:1px'>" + "<div class='knob_lfo_body' id='" + element.id + "_rate_body'>" + "<div class='knob_lfo_knob' id='" + element.id + "_rate_knob'>" + "<div class='knob_lfo_arrow'>&nbsp;</div></div></div>" + "<div class='knob_lfo_label'>rate</div>" + "</div>"

    + "<div class='knob_lfo' id='" + element.id + "_modamt' title='Amount'>" + "<div class='knob_lfo_body' id='" + element.id + "_modamt_body'>" + "<div class='knob_lfo_knob' id='" + element.id + "_modamt_knob'>" + "<div class='knob_lfo_arrow'>&nbsp;</div></div></div>" + "<div class='knob_lfo_label'>amt</div>"

    + "</div>";

    var knobs = [element.id, element.id + "_rate", element.id + "_modamt"];
    var values = [initValue, 0, 0];
    for (var i = 0; i < knobs.length; i++) {
        var knob = document.getElementById(knobs[i]);
        var knobBody = document.getElementById(knobs[i] + "_body");

        knob.value = values[i];
        knobBody.onclick = knobOnClick;
        knobBody.onmousemove = knobOnMouseMove;
        knobBody.onmousedown = knobOnMouseDown;
        knobBody.onmouseout = knobOnMouseOut;
        knob.ondrag = knobOnDrag;
        knobUpdate(knob);
    }

}

function knobGetElement(event) {
    var element = eGetElement(event);
    while (element.className != "knob" && element.className != "knob_lfo") element = element.parentNode;
    return element;
}

function knobUpdate(element) {
    var knob = document.getElementById(element.id + "_knob");
    knob.style.MozTransform = "rotate(" + (270 * Number(element.value) - 45) + "deg)";
    knob.style.WebkitTransform = "rotate(" + (270 * Number(element.value) - 45) + "deg)";

    var input = document.getElementById(element.id + "_input");
    if (input) {
        input.value = element.value;
    }

    if (element.id in document.controls) document.controls[element.id].knobValue = element.value;
    else if (element.parentNode.id in document.controls) { // lfo knob
        var expValue = Math.pow(element.value, 3);
        if (element.title == "Amount") document.controls[element.parentNode.id].lfoAmount = expValue;
        else if (element.title == "Rate") document.controls[element.parentNode.id].lfoRate = expValue;
    }
}

function knobOnLfoChange(element) {
    var lfoType = element.value;
    document.getElementById(element.parentNode.id + "_lfo_type").innerHTML = "LFO: " + lfoType;
    document.controls[element.parentNode.id].lfoType = lfoType;
}

function knobOnDrag(event) {
    var x = eGetX(event) - document.dragX;
    var y = eGetY(event) - document.dragY;
    var element = document.dragElement;
    element.value = Math.max(Math.min(Number(document.dragValue) - (Math.pow(y / 50, 3)), 1), 0);
    knobUpdate(element);
}

function knobOnClick(event) {}

function knobOnMouseMove(event) {}

function knobOnMouseDown(event) {
    document.dragElement = knobGetElement(event);
    document.dragX = eGetX(event);
    document.dragY = eGetY(event);
    document.dragValue = document.dragElement.value;
}

function knobOnMouseOut(event) {}

init();
    <canvas id="canvas"></canvas>

<div id="copyright">&copy; Tim Wessman, 2012</div>
<div id="showHide" onclick="var controls = document.getElementById('controls');controls.style.display = controls.style.display == 'none' ? 'block' : 'none';this.innerHTML = controls.style.display == 'none' ? 'showControls' : 'hideControls';">hideControls</div>

    <div id="controls">
                
        <div class="knob_group">
                <div class="label"><div class="label_text">spirograph</div></div>
                <div class="knob" id="sp_l" title="L">0.71</div>
                <div class="knob" id="sp_k" title="K">0.71</div>
                <div class="knob" id="sp_T" title="length">0.2</div>
                <div class="knob" id="sp_T2" title="length2">0.2</div>
                <div class="knob" id="sp_R" title="size">0.35</div>
                <div class="knob" id="lineWidth" title="width">0.4</div>
        </div>

        <div class="knob_group">
                <div class="label"><div class="label_text">color</div></div>    
                <div class="knob" id="red" title="red">0.15</div>
                <div class="knob" id="green" title="green">1</div>
                <div class="knob" id="blue" title="blue">0.90</div>
                <div class="knob" id="alpha" title="alpha">0.5</div>
        </div>

        <div class="knob_group">
                <div class="label"><div class="label_text">background</div></div>    
                <div class="knob" id="bgRed" title="red"></div>
                <div class="knob" id="bgGreen" title="green"></div>
                <div class="knob" id="bgBlue" title="blue"></div>
                <div class="knob" id="bgAlpha" title="alpha">0.17</div>
        </div>

        <div class="knob_group">
                <div class="label"><div class="label_text">3d</div></div>    
                <div class="knob" id="x3D" title="x3D">0</div>
                <div class="knob" id="y3D" title="y3D">0</div>
                <div class="knob" id="rotateX" title="rotX">0.50</div>
                <div class="knob" id="rotateY" title="rotY">0.50</div>
                <div class="knob" id="rotateZ" title="rotZ">0.51</div>
                <div class="knob" id="zOffset" title="zOffset">0.35</div>
                <div class="knob" id="zScale" title="zScale">0</div>
        </div>

        <div class="knob_group">
                <div class="label"><div class="label_text">extra</div></div>    
                <div class="knob" id="posX" title="posX" lfo="">0.3</div>
                <div class="knob" id="posY" title="posY">0.5</div>
                <div class="knob" id="sp_t" title="step">0.1</div>
                <div class="knob" id="anim" title="anim">0.1</div>
                <div class="knob" id="slow" title="slow">0.1</div>
        </div>
    </div>
div, body, input {
    font-family: Arial, sans-serif;
    color: white;
    margin: 0px;
}
div, body {
    -moz-user-select: none;
    -webkit-user-select: none;     
}
body {
    background: black;
}
input {
    -moz-user-select: text;
    -webkit-user-select: text;    
    background: transparent;
}

#canvas {width:100%;height:100%;cursor:crosshair;position:fixed}
#copyright {position:fixed;left:0px;top:0px;color:gray;font-weight:bold;font-size:12px;margin:5px}
#showHide {position:fixed;right:0px;top:0px;color:gray;font-weight:bold;cursor:pointer;margin:5px}
#controls {width:400px;height:100%;position:absolute;right:0px;top:50px;display:inline-block;background:transparent}

.knob_group {display: inline-block;height: 120px;}
.knob {  
    display:inline-block;
    border: 1px solid gray;
    border-radius: 3px 3px 3px 3px;
    height: 111px;
    padding-top: 0px;
    width: 43px;
}
.knob_body {
    border-radius: 15px 15px 15px 15px;
    box-shadow: 0 0 5px 1px white;
    height: 31px;
    margin: 0px 6px;
    width: 31px;
    -moz-user-select: none;
    -webkit-user-select: none;
}
.knob_knob {
    background-color: transparent;
    cursor: pointer;
    height: 31px;
    width: 31px;
}
.knob_arrow {
    position:absolute;
    display:inline-block;
    top: 15px;
    width: 15px;
    height: 1px;
    background-color: yellow;
}
.knob_label {
    diplay: inline-block;
    font-size: 9px;
    text-align:center;
    margin: 2px 0px 6px 0px;
    
}
.knob_input {
    display:inline-block;
    width: 100%;
    font-size: 8px;
    border: 0px;
    margin: 5px 0px 0px 0px;
    text-align:center;
}
.knob_min_input {
    display:inline-block;
    width: 18px;
    font-size: 6px;
    border: 0px;
    margin: 0px 0px -10px 2px;
    text-align:left;
    color: yellow;
}
.knob_max_input {
    display:inline-block;
    width: 18px;
    font-size: 6px;
    border: 0px;
    margin: 0px 0px -10px 3px;
    text-align:right;
    color: yellow;
}
.knob_lfo_type {
    margin-top: 2px;
    font-size: 8px;
    color: yellow;
    text-align: center;
}
.knob_lfo_type_select {
//    font-size: 8px;
//    border: 0px;
        background: black;
        border: 0px;
        opacity: 0;
        height: 10px;
        position: relative;
        top: -12px;
    margin: 3px 2px 0px 2px;
    text-align:center;
}

.knob_lfo {
    display: inline-block;
    position: relative;
    top: -12px;
}

.knob_lfo_body {
    border-radius: 8px 8px 8px 8px;
    box-shadow: 0 0 5px 0px white;
    height: 15px;
    margin: 3px 3px;
    width: 15px;
    -moz-user-select: none;
    -webkit-user-select: none;
    background-color: transparent;
}
.knob_lfo_knob {
    background-color: transparent;
    cursor: pointer;
    height: 15px;
    width: 15px;
}
.knob_lfo_arrow {
    position:absolute;
    display:inline-block;
    top: 7px;
    width: 7px;
    height: 1px;
    background-color: yellow;
}
.knob_lfo_label {
    diplay: block;
    font-size: 7px;
    text-align:center;
}



.label {
    display: inline-block;
    width: 10px;
    height: 60px;
}
.label_text {
    display: inline-block;
    position: relative;
    
    width: 60px;
    height: 10px;
    font-size: 9px;
    -moz-transform: rotate(270deg);
    -webkit-transform: rotate(270deg);
    left:-24px;
    top: -37px;
}