// ruler.js -- click-and-drag ruler implemented with jQuery and Raphel
// see http://jeremyslade.com/articles/2008/12/17/implementing-a-ruler-with-raphael-and-jquery/

$(document).ready(function(){
  var paper = $("#paper");
  paper[0].ruler = new Ruler(paper[0]);
});

var Ruler = function (elem) {
  elem = $(elem);
  this.elem = elem[0];
  this.raph = new Raphael(elem[0],elem.width(),elem.height());

  var b = this;
  elem.mousedown(function(e) { b.start(e); });
  elem.mouseup(function(e) { b.finish(e); });
  elem.mousemove(function(e) { b.move(e); });
};


Ruler.methods = {
  start: function(e) {
    if ( this.start_at ) return;
    this.offset = $(this.elem).offset();
    this.start_at = { left: e.pageX - this.offset.left,
                      top: e.pageY - this.offset.top };

    // Create the path
    this.path = this.raph.path({stroke:'red','stroke-width':'2px'}).
      moveTo(this.start_at.left,this.start_at.top).
      lineTo(this.start_at.left,this.start_at.top).
      lineTo(this.start_at.left,this.start_at.top);

    // Create the text labels
    this.hlabel = $('<div style="position:absolute;color:red;"></div>').
      appendTo(document.body);
    this.vlabel = $('<div style="position:absolute;color:red;"></div>').
      appendTo(document.body);
    this.unselectable(this.hlabel[0]);
    this.unselectable(this.vlabel[0]);

    this.dir = null; // initially un-biased
    this.move(e);

    return false;
  },

  finish: function(e) {
    this.start_at = null;
    try { 
      this.path[0].parentNode.removeChild(this.path[0]);
      this.hlabel[0].parentNode.removeChild(this.hlabel[0]);
      this.vlabel[0].parentNode.removeChild(this.vlabel[0]);
    } catch(e) { };
    return false;
  },

  move: function(e) {
    if ( !this.start_at ) return;
    var left = e.pageX - this.offset.left;
    var top = e.pageY - this.offset.top;
    this.draw(left,top);
    return false;
  },

  draw: function(left,top) {
    this.dx = (left - this.start_at.left);
    this.dy = (top - this.start_at.top);
    if ( !this.dir ) this.bias(left,top);
    this.draw_lines(left,top);
    this.draw_labels(left,top);
  },

  bias: function(left,top) {
    var dx = Math.abs(this.dx);
    var dy = Math.abs(this.dy)
    if ( (dx+dy) > 10 )
      this.dir = (dx > dy) ? 'h':'v';
  },

  draw_lines: function(left,top) {
    var p = this.path.path;
    if ( this.dir == 'h' )
      p[1].arg = [left, this.start_at.top];
    else
      p[1].arg = [this.start_at.left, top];
    p[2].arg = [left, top];
    this.path.redraw();
  },

  draw_labels: function(left,top) {
    var hl, ht, vl, vt;
    if ( this.dir == 'h' ) {
      // horz label
      hl = (this.start_at.left + left)/2;
      ht = this.start_at.top;
      // vert label
      vl = left + 2;
      vt = (this.start_at.top + top)/2;
    } else {
      // horz label
      hl = (this.start_at.left + left)/2;
      ht = top;
      // vert label
      vl = this.start_at.left + 2;
      vt = (this.start_at.top + top)/2;
    }
    $(this.hlabel).text(this.dx).
      css({left: (this.offset.left + hl)+"px",
           top: (this.offset.top + ht)+"px"});
    $(this.vlabel).text(this.dy).
      css({left: (this.offset.left + vl)+"px",
           top: (this.offset.top + vt)+"px"});
  },

  unselectable: function(element) {
    // http://ajaxcookbook.org/disable-text-selection/
    element.onselectstart = function() { return false; }
    element.unselectable = "on";
    element.style.MozUserSelect = "none";
  }

};
$.extend(Ruler.prototype,Ruler.methods);

