Christmas JS1k

December 29, 2010

Gifted the benefit of R&D time at work, at the end of 2010 I submitted an entry to the Christmas JS1k contest along with my fellow POPsters. I got to geek out and spend work time creating something cutting-edge that I'm pretty proud of: a canvas drawing app!

My goals were to:

  • Learn enough native JS to complete an entry(!)
  • Use canvas
  • Keep usability in mind since it tends to go out the window when shaving off bytes: cursors, tip text, etc.

To see what I ended up with (as well as a super fancy jQuery version that was my starting point), you can play with a demo here.

What is JS1k, you ask? From the source: "the object of this competition is to create a cool JavaScript "application" no larger than 1k. Starting out as a joke, the first version ended with a serious amount of submissions, prizes and quality."

View my uncompressed JS1k entry

<script type="text/javascript">
    var c = document.getElementsByTagName('canvas')[0];
    var b = document.body;
    var a = c.getContext('2d');
    </script> 
    <script type="text/javascript">
    d=document;
    
    h=d.createElement('h1');
    h.innerHTML='Draw.';
    b.insertBefore(h, c);
    
    // context abbreviation loop
    for($ in a){
        a[$[0]+($[6]||$[2])]=a[$];
    }
    
    // commonly used integers
    x=150;
    y=120;
    
    c.width=c.height=x*2;
    k='background:#';
    z=c.style;
    z.cssText=k+"416012";
    
    // pen color array
    A=['000','0e943a','C0C0C0','C5B358'];
    co = '#'+A[0];
    
    //create color squares
    for(i=0;i<4;i++){
      sqr(A[i]);
    }
    // not overlapping circle
    oLp = 0;
    // not drawing
    drw = 0;
    
    onmousemove=function(e){
    
        // get mouse/canvas properties
        gTs(e,c)
        
        // mouse intersects circle
        if(dI(eX-oL, eY-oT)){
            
            z.cursor='crosshair';
            oLp = 1;
            // if the mouse is down, leave a mark
            if (drw == 1) {
            with(a){
                    ln(eX-oL, eY-oT); // lineTo
                    strokeStyle = co;
                    sr() // stroke
                }
            }
        }
        // mouse off circle
        else {
            z.cursor='default';
            oLp = 0;
            drw = 0
        }
    };
    onmouseup=function(){ drw = 0}
    onmousedown=function(e){
        // if overlapping
        if(oLp) {
            gTs(e,e.target)
            drw = 1;
            with(a){
                ba(); // beginPath
                lineWidth=3;
                mv(eX-oL, eY-oT) // moveTo
            }
        }
    }
    // get target values
    function gTs(e,t){
        eX=e.pageX;
        eY=e.pageY;
        oL=t.offsetLeft;
        oT=t.offsetTop;
    }
    // create square: k='background:#', v=color from array
    function sqr(v){
        n=d.createElement('a');
        n.id=v;
        n.style.cssText=k + v +';cursor:pointer;height:15px;float:left;margin:0 8px 0 0;width:15px';
        n.onclick=function(e){co='#'+e.target.id}
        b.appendChild(n)
    }
    // does intersect: a=pageX, b=pageY, x=circleX/circleY, y=circleRadius
    function dI(a,b) {
        f = a-x;
        g = b-x;
        return f*f+g*g <= y*y
    }
    // create sphere
    with(a){
        g=cR(x,y,0,x,y,200); // createRadialGradient
        g.addColorStop(0,'#f00');
        g.addColorStop(1,'#600');
        ba(); // beginPath
        fillStyle=g;
        ac(x, x, y, 0, Math.PI*2,false); // arc
        ca(); // closePath
        fl() // fill
    }
    </script>