/** * @author Szymon DziaƂowski * @homepage https://bitbucket.org/stopsopa/jquery.line * @ver 1.0 2014-07-06 * @ver 1.1 2014-07-07 upgrades, corrections * @ver 1.2 2015-05-01 drawing line by rad/ang and distance from point x and x, fix manual */ (function( factory ) { if ( typeof define === "function" && define.amd ) { // AMD. Register as an anonymous module. define([ "jquery" ], factory ); } else { // Browser globals factory( jQuery ); } })((function (name, pi) { return function ($) { function log(l) {try {console.log(l);}catch (e) {}}; function error(l) {try {console.error(l);}catch (e) {}}; function _thw(message) {throw "plugin jQuery(...)."+name+"() : "+message}; function _a(a) { return Array.prototype.slice.call(a, 0); } function isFunction (a) { // taken from underscore.js return typeof a == 'function' || false; }; function isObject(obj) { var type = typeof obj; return type === 'function' || type === 'object' && !!obj; }; function angToRad(ang) { return ang * (pi / 180); } function radToAng(rad) { return rad * (180 / pi) ; } // calc distance between two points function calcDistance(x1, y1, x2, y2) { // http://www.gwycon.com/calculating-the-distance-between-two-pixels/ return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); } // count angle in radians function calcAngleRad(x1, y1, x2, y2) { return Math.atan2( (y2 - y1) , (x2 - x1) ); } // count angle in degrees function calcAngle(x1, y1, x2, y2) { var a = calcAngleRad(x1, y1, x2, y2) * (180 / pi); return (a < 0) ? (a += 360) : a; } function calcXYOffsetByVectorAngleRad(rad, dis) { return { // http://stackoverflow.com/a/10962780 x : Math.cos(rad) * dis, y : Math.sin(rad) * dis } } function calcXYOffsetByVectorAngle(ang, dis) { return calcXYOffsetByVectorAngleRad(angToRad(ang), dis); } // count correction function correct(x1, y1, x2, y2, o, ang) { ang || (ang = calcAngle(x1, y1, x2, y2)); var hw = o.width/2; var hwo = hw // originial var sw = false; if ($.isNumeric(o.correct)) { var c = o.correct; switch(true) { case o.correctpos == 'normal': hw += c; break; case o.correctpos == 'top' && (ang > 90 && ang < 270) : sw = true; c = - Math.abs(c); break; case o.correctpos == 'bottom' && (ang < 90 || ang > 270) : sw = true; c = - Math.abs(c); break; case o.correctpos == 'left' && (ang > 0 && ang < 180) : sw = true; c = - Math.abs(c); break; case o.correctpos == 'right' && (ang < 0 || ang > 180) : sw = true; c = - Math.abs(c); break; } hw += c; } var rad = calcAngleRad(x1, y1, x2, y2); // radians var radminhalf = (rad - (pi / 2)); // radians minus half radian var c = {}; if (o.correct === false) { c.x = c.y = c.oy = c.ox = 0; } else { c.y = Math.sin(radminhalf) * hw; c.x = Math.cos(radminhalf) * hw; c.oy = Math.sin(radminhalf) * hwo; // without correction c.ox = Math.cos(radminhalf) * hwo; // without correction } c.ang = ang; c.rad = rad c.ox2 = c.ox * 2; c.oy2 = c.oy * 2; c.x1 = x1; c.y1 = y1; c.x2 = x2; c.y2 = y2; if (sw) { c.ax = c.x1 - c.ox2; c.ay = c.y1 - c.oy2; c.bx = c.ax + c.x; c.by = c.ay + c.y; c.cx = c.x2 + c.x c.cy = c.y2 + c.y; c.dx = c.cx - c.ox2; c.dy = c.cy - c.oy2; } else { c.bx = c.x1 + c.x; c.by = c.y1 + c.y; c.ax = c.bx - c.ox2; c.ay = c.by - c.oy2; c.dx = c.x2 + c.x; c.dy = c.y2 + c.y; c.cx = c.dx - c.ox2 c.cy = c.dy - c.oy2; } return c; } /** * @returns jQuery object representing line * var linediv = $.line(x1, y1, x2, y2, opt, callback); * var linediv = $('parent element').line(x1, y1, x2, y2, opt, callback); * var linediv = $('parent element').line(x1, y1, {ang: 45, dis: 200}, opt, callback); * var linediv = $.line(x1, y1, {ang: 45, dis: 200}, opt, callback); */ //0 1 2 3 4 5 $.fn[name] = function (x1, y1, x2, y2, opt, callback) { if (isObject(x2)) { var k = 0, a = _a(arguments); if (typeof x2.ang != 'undefined') k = calcXYOffsetByVectorAngle(x2.ang, x2.dis); else if (typeof x2.rad != 'undefined') k = calcXYOffsetByVectorAngleRad(x2.rad, x2.dis); else _thw("Arguments incomplete: "+JSON.stringify(a)); a[5] = a[4]; a[4] = a[3]; a[2] = x1 + k.x; a[3] = y1 + k.y; log(a); return $.fn[name].apply(this, a); } if (isFunction(opt)) { callback = opt; } else if (isFunction(callback)) { opt = callback; } opt || (opt = {}); if ($(this).length > 1) throw "$(this) is more then one element"; var o = { style: 'solid', width: 1, color: 'black', cls: 'jqline', id: false, correct: true, // bool|int - corection of position, give integer to move correctpos: 'normal', // normal, top, bottom, left, right css: { height: '0', zIndex: '999', zoom: 1 } } if (opt.css) { $.extend(o.css, opt.css); opt.css = o.css; } o = $.extend(true, o, opt || {}); o.create = opt.create ? $(opt.create) : $('
'); var ang = calcAngle(x1, y1, x2, y2); // degrees var c = correct(x1, y1, x2, y2, o/* half of line width */, ang); c.distance = calcDistance(x1, y1, x2, y2); o.create .css({ borderTop: o.width+'px '+o.style+' '+o.color, position: 'absolute', width: c.distance + 'px', '-webkit-transform': 'rotate(' + ang + 'deg)', '-moz-transform': 'rotate(' + ang + 'deg)', '-ms-transform': 'rotate(' + ang + 'deg)', '-o-transform': 'rotate(' + ang + 'deg)', transform: 'rotate(' + ang + 'deg)', 'transform-origin' : '0 0', '-ms-transform-origin' : '0 0', /* IE 9 */ '-webkit-transform-origin' : '0 0', /* Chrome, Safari, Opera */ left : (x1 + c.x)+'px', top : (y1 + c.y)+'px' }) .css(o.css) ; o.cls && o.create.addClass(o.cls); o.id && o.create.attr('id', o.id); o.create.appendTo(this); (isFunction(callback)) && callback(o.create, o, c); return o.create; }; /** * @returns jQuery object representing line */ $[name] = function () { var b = $('body'); return b[name].apply(b, arguments); }; // expose tools to use outside $[name].radToAng = radToAng; $[name].angToRad = angToRad; $[name].calcDistance = calcDistance; $[name].calcAngleRad = calcAngleRad; $[name].calcAngle = calcAngle; $[name].calcXYOffsetByVectorAngle = calcXYOffsetByVectorAngle; $[name].calcXYOffsetByVectorAngleRad = calcXYOffsetByVectorAngleRad; } })('line', Math.PI)); // to change name of plugin simply change it in this place