jquery.line.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /**
  2. * @author Szymon Działowski
  3. * @homepage https://bitbucket.org/stopsopa/jquery.line
  4. * @ver 1.0 2014-07-06
  5. * @ver 1.1 2014-07-07 upgrades, corrections
  6. * @ver 1.2 2015-05-01 drawing line by rad/ang and distance from point x and x, fix manual
  7. */
  8. (function( factory ) {
  9. if ( typeof define === "function" && define.amd ) {
  10. // AMD. Register as an anonymous module.
  11. define([ "jquery" ], factory );
  12. } else {
  13. // Browser globals
  14. factory( jQuery );
  15. }
  16. })((function (name, pi) {
  17. return function ($) {
  18. function log(l) {try {console.log(l);}catch (e) {}};
  19. function error(l) {try {console.error(l);}catch (e) {}};
  20. function _thw(message) {throw "plugin jQuery(...)."+name+"() : "+message};
  21. function _a(a) {
  22. return Array.prototype.slice.call(a, 0);
  23. }
  24. function isFunction (a) { // taken from underscore.js
  25. return typeof a == 'function' || false;
  26. };
  27. function isObject(obj) {
  28. var type = typeof obj;
  29. return type === 'function' || type === 'object' && !!obj;
  30. };
  31. function angToRad(ang) {
  32. return ang * (pi / 180);
  33. }
  34. function radToAng(rad) {
  35. return rad * (180 / pi) ;
  36. }
  37. // calc distance between two points
  38. function calcDistance(x1, y1, x2, y2) { // http://www.gwycon.com/calculating-the-distance-between-two-pixels/
  39. return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
  40. }
  41. // count angle in radians
  42. function calcAngleRad(x1, y1, x2, y2) {
  43. return Math.atan2( (y2 - y1) , (x2 - x1) );
  44. }
  45. // count angle in degrees
  46. function calcAngle(x1, y1, x2, y2) {
  47. var a = calcAngleRad(x1, y1, x2, y2) * (180 / pi);
  48. return (a < 0) ? (a += 360) : a;
  49. }
  50. function calcXYOffsetByVectorAngleRad(rad, dis) {
  51. return { // http://stackoverflow.com/a/10962780
  52. x : Math.cos(rad) * dis,
  53. y : Math.sin(rad) * dis
  54. }
  55. }
  56. function calcXYOffsetByVectorAngle(ang, dis) {
  57. return calcXYOffsetByVectorAngleRad(angToRad(ang), dis);
  58. }
  59. // count correction
  60. function correct(x1, y1, x2, y2, o, ang) {
  61. ang || (ang = calcAngle(x1, y1, x2, y2));
  62. var hw = o.width/2;
  63. var hwo = hw // originial
  64. var sw = false;
  65. if ($.isNumeric(o.correct)) {
  66. var c = o.correct;
  67. switch(true) {
  68. case o.correctpos == 'normal':
  69. hw += c;
  70. break;
  71. case o.correctpos == 'top' && (ang > 90 && ang < 270) :
  72. sw = true;
  73. c = - Math.abs(c);
  74. break;
  75. case o.correctpos == 'bottom' && (ang < 90 || ang > 270) :
  76. sw = true;
  77. c = - Math.abs(c);
  78. break;
  79. case o.correctpos == 'left' && (ang > 0 && ang < 180) :
  80. sw = true;
  81. c = - Math.abs(c);
  82. break;
  83. case o.correctpos == 'right' && (ang < 0 || ang > 180) :
  84. sw = true;
  85. c = - Math.abs(c);
  86. break;
  87. }
  88. hw += c;
  89. }
  90. var rad = calcAngleRad(x1, y1, x2, y2); // radians
  91. var radminhalf = (rad - (pi / 2)); // radians minus half radian
  92. var c = {};
  93. if (o.correct === false) {
  94. c.x = c.y = c.oy = c.ox = 0;
  95. }
  96. else {
  97. c.y = Math.sin(radminhalf) * hw;
  98. c.x = Math.cos(radminhalf) * hw;
  99. c.oy = Math.sin(radminhalf) * hwo; // without correction
  100. c.ox = Math.cos(radminhalf) * hwo; // without correction
  101. }
  102. c.ang = ang;
  103. c.rad = rad
  104. c.ox2 = c.ox * 2;
  105. c.oy2 = c.oy * 2;
  106. c.x1 = x1;
  107. c.y1 = y1;
  108. c.x2 = x2;
  109. c.y2 = y2;
  110. if (sw) {
  111. c.ax = c.x1 - c.ox2;
  112. c.ay = c.y1 - c.oy2;
  113. c.bx = c.ax + c.x;
  114. c.by = c.ay + c.y;
  115. c.cx = c.x2 + c.x
  116. c.cy = c.y2 + c.y;
  117. c.dx = c.cx - c.ox2;
  118. c.dy = c.cy - c.oy2;
  119. }
  120. else {
  121. c.bx = c.x1 + c.x;
  122. c.by = c.y1 + c.y;
  123. c.ax = c.bx - c.ox2;
  124. c.ay = c.by - c.oy2;
  125. c.dx = c.x2 + c.x;
  126. c.dy = c.y2 + c.y;
  127. c.cx = c.dx - c.ox2
  128. c.cy = c.dy - c.oy2;
  129. }
  130. return c;
  131. }
  132. /**
  133. * @returns jQuery object representing line
  134. * var linediv = $.line(x1, y1, x2, y2, opt, callback);
  135. * var linediv = $('parent element').line(x1, y1, x2, y2, opt, callback);
  136. * var linediv = $('parent element').line(x1, y1, {ang: 45, dis: 200}, opt, callback);
  137. * var linediv = $.line(x1, y1, {ang: 45, dis: 200}, opt, callback);
  138. */ //0 1 2 3 4 5
  139. $.fn[name] = function (x1, y1, x2, y2, opt, callback) {
  140. if (isObject(x2)) {
  141. var k = 0, a = _a(arguments);
  142. if (typeof x2.ang != 'undefined')
  143. k = calcXYOffsetByVectorAngle(x2.ang, x2.dis);
  144. else if (typeof x2.rad != 'undefined')
  145. k = calcXYOffsetByVectorAngleRad(x2.rad, x2.dis);
  146. else _thw("Arguments incomplete: "+JSON.stringify(a));
  147. a[5] = a[4];
  148. a[4] = a[3];
  149. a[2] = x1 + k.x;
  150. a[3] = y1 + k.y;
  151. log(a);
  152. return $.fn[name].apply(this, a);
  153. }
  154. if (isFunction(opt)) {
  155. callback = opt;
  156. }
  157. else if (isFunction(callback)) {
  158. opt = callback;
  159. }
  160. opt || (opt = {});
  161. if ($(this).length > 1)
  162. throw "$(this) is more then one element";
  163. var o = {
  164. style: 'solid',
  165. width: 1,
  166. color: 'black',
  167. cls: 'jqline',
  168. id: false,
  169. correct: true, // bool|int - corection of position, give integer to move
  170. correctpos: 'normal', // normal, top, bottom, left, right
  171. css: {
  172. height: '0',
  173. zIndex: '999',
  174. zoom: 1
  175. }
  176. }
  177. if (opt.css) {
  178. $.extend(o.css, opt.css);
  179. opt.css = o.css;
  180. }
  181. o = $.extend(true, o, opt || {});
  182. o.create = opt.create ? $(opt.create) : $('<div></div>');
  183. var ang = calcAngle(x1, y1, x2, y2); // degrees
  184. var c = correct(x1, y1, x2, y2, o/* half of line width */, ang);
  185. c.distance = calcDistance(x1, y1, x2, y2);
  186. o.create
  187. .css({
  188. borderTop: o.width+'px '+o.style+' '+o.color,
  189. position: 'absolute',
  190. width: c.distance + 'px',
  191. '-webkit-transform': 'rotate(' + ang + 'deg)',
  192. '-moz-transform': 'rotate(' + ang + 'deg)',
  193. '-ms-transform': 'rotate(' + ang + 'deg)',
  194. '-o-transform': 'rotate(' + ang + 'deg)',
  195. transform: 'rotate(' + ang + 'deg)',
  196. 'transform-origin' : '0 0',
  197. '-ms-transform-origin' : '0 0', /* IE 9 */
  198. '-webkit-transform-origin' : '0 0', /* Chrome, Safari, Opera */
  199. left : (x1 + c.x)+'px',
  200. top : (y1 + c.y)+'px'
  201. })
  202. .css(o.css)
  203. ;
  204. o.cls && o.create.addClass(o.cls);
  205. o.id && o.create.attr('id', o.id);
  206. o.create.appendTo(this);
  207. (isFunction(callback)) && callback(o.create, o, c);
  208. return o.create;
  209. };
  210. /**
  211. * @returns jQuery object representing line
  212. */
  213. $[name] = function () {
  214. var b = $('body');
  215. return b[name].apply(b, arguments);
  216. };
  217. // expose tools to use outside
  218. $[name].radToAng = radToAng;
  219. $[name].angToRad = angToRad;
  220. $[name].calcDistance = calcDistance;
  221. $[name].calcAngleRad = calcAngleRad;
  222. $[name].calcAngle = calcAngle;
  223. $[name].calcXYOffsetByVectorAngle = calcXYOffsetByVectorAngle;
  224. $[name].calcXYOffsetByVectorAngleRad = calcXYOffsetByVectorAngleRad;
  225. }
  226. })('line', Math.PI)); // to change name of plugin simply change it in this place