// 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 = $('
'). appendTo(document.body); this.vlabel = $(''). 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);