tdrag.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. /*! Tdrag 0.0.1 */
  2. /**
  3. * Created by Tezml on 2016/5/26
  4. * You can modify my source code, if you have a good idea or a problem can be encountered by e-mail: tezml@tezml.com to find me.
  5. * 如果你想在项目中使用该插件,请不要删除该注释。
  6. */
  7. ;(function($,window,document,undefined){
  8. jQuery(function() {
  9. //插件制作
  10. $.fn.Tdrag = function (opt) {
  11. var call = {
  12. scope: null,//父级
  13. grid: null,//网格
  14. axis:"all",//上下或者左右
  15. pos:false,//是否记住位置
  16. handle:null,//手柄
  17. moveClass:"tezml",//移动时不换位加的class
  18. dragChange:false,//是否开启拖拽换位
  19. changeMode:"point",//point & sort
  20. cbStart:function(){},//移动前的回调函数
  21. cbMove:function(){},//移动中的回调函数
  22. cbEnd:function(){},//移动结束时候的回调函数
  23. random:false,//是否自动随机排序
  24. randomInput:null,//点击随机排序的按钮
  25. animation_options:{//运动时的参数
  26. duration:800,//每次运动的时间
  27. easing:"ease-out"//移动时的特效,ease-out、ease-in、linear
  28. },
  29. disable:false,//禁止拖拽
  30. disableInput:null//禁止拖拽的按钮
  31. };
  32. var dragfn = new Dragfn(this, opt);
  33. if (opt && $.isEmptyObject(opt) == false) {
  34. dragfn.options = $.extend(call, opt);
  35. } else {
  36. dragfn.options = call;
  37. }
  38. dragfn.firstRandom=true;
  39. var ele = dragfn.$element;
  40. dragfn.pack(ele,false);
  41. if(dragfn.options.randomInput!=null){
  42. $(dragfn.options.randomInput).bind("click",function(){
  43. dragfn.pack(ele,true);
  44. })
  45. }
  46. //加载拓展jquery的函数
  47. dragfn.loadJqueryfn()
  48. };
  49. //依赖构造函数
  50. var Dragfn = function (ele, opt) {
  51. this.$element = ele;
  52. this.options = opt;
  53. };
  54. //构造函数方法
  55. Dragfn.prototype = {
  56. init: function (obj) {
  57. var self = this;
  58. self.ele=self.$element;
  59. self.handle=$(obj);//手柄
  60. self.options = self.options;
  61. self.disable = self.options.disable;
  62. self._start = false;
  63. self._move = false;
  64. self._end = false;
  65. self.disX = 0;
  66. self.disY = 0;
  67. self.zIndex=1000;
  68. self.moving=false;
  69. self.moves="";
  70. //父级
  71. self.box = $.type(self.options.scope)==="string" ? self.options.scope : null;
  72. //手柄
  73. if(self.options.handle!=null){
  74. self.handle=$(obj).find(self.options.handle);
  75. }
  76. //三个事件
  77. self.handle.on("mousedown", function (ev) {
  78. self.start(ev, obj);
  79. obj.setCapture && obj.setCapture();
  80. return false;
  81. });
  82. if(self.options.dragChange) {
  83. $(obj).on("mousemove", function (ev) {
  84. self.move(ev, obj);
  85. });
  86. $(obj).on("mouseup", function (ev) {
  87. self.end(ev, obj);
  88. });
  89. }else{
  90. $(document).on("mousemove", function (ev) {
  91. self.move(ev, obj);
  92. });
  93. $(document).on("mouseup", function (ev) {
  94. self.end(ev, obj);
  95. });
  96. }
  97. },
  98. //jquery调取函数时候用
  99. loadJqueryfn: function(){
  100. var self=this;
  101. $.extend({
  102. //返回按照index排序的回调函数
  103. sortBox:function(obj){
  104. var arr=[];
  105. for (var s = 0; s < $(obj).length; s++) {
  106. arr.push($(obj).eq(s));
  107. }
  108. for ( var i = 0; i < arr.length; i++) {
  109. for ( var j = i + 1; j < arr.length; j++) {
  110. if(Number(arr[i].attr("index")) > Number(arr[j].attr("index"))){
  111. var temp = arr[i];
  112. arr[i] = arr[j];
  113. arr[j] = temp;
  114. }
  115. }
  116. }
  117. return arr
  118. },
  119. //随机排序函数
  120. randomfn:function(obj){
  121. self.pack($(obj),true);
  122. },
  123. //开启拖拽
  124. disable_open:function(){
  125. self.disable=false;
  126. },
  127. //禁止拖拽
  128. disable_cloose:function(){
  129. self.disable=true;
  130. }
  131. });
  132. },
  133. toDisable: function(){
  134. var self=this;
  135. if(self.options.disableInput!=null){
  136. $(self.options.disableInput).bind("click",function(){
  137. if(self.disable==true){
  138. self.disable=false
  139. }else{
  140. self.disable=true
  141. }
  142. })
  143. }
  144. },
  145. start: function (ev, obj) {
  146. var self = this;
  147. self.moved=obj;
  148. if (self.disable == true) {
  149. return false
  150. }
  151. self._start = true;
  152. var oEvent = ev || event;
  153. self.disX = oEvent.clientX - obj.offsetLeft;
  154. self.disY = oEvent.clientY - obj.offsetTop;
  155. $(obj).css("zIndex",self.zIndex++);
  156. self.options.cbStart();
  157. },
  158. move: function (ev, obj) {
  159. var self = this;
  160. if (self._start != true) {
  161. return false
  162. }
  163. if(obj!=self.moved){
  164. return false
  165. }
  166. self._move = true;
  167. var oEvent = ev || event;
  168. var l = oEvent.clientX - self.disX;
  169. var t = oEvent.clientY - self.disY;
  170. //有父级限制
  171. if (self.box != null) {
  172. var rule = self.collTestBox(obj,self.box);
  173. if (l > rule.lmax) {
  174. l = rule.lmax;
  175. } else if (l < rule.lmin) {
  176. l = rule.lmin;
  177. }
  178. if (t > rule.tmax) {
  179. t = rule.tmax;
  180. } else if (t < rule.tmin) {
  181. t = rule.tmin;
  182. }
  183. }
  184. if(self.options.axis=="all"){
  185. obj.style.left = self.grid(obj, l, t).left + 'px';
  186. obj.style.top = self.grid(obj, l, t).top + 'px';
  187. }else if(self.options.axis=="y"){
  188. obj.style.top = self.grid(obj, l, t).top + 'px';
  189. }else if(self.options.axis=="x"){
  190. obj.style.left = self.grid(obj, l, t).left + 'px';
  191. }
  192. /* if(self.options.changeWhen=="move") {
  193. if (self.options.changeMode == "sort") {
  194. self.sortDrag(obj);
  195. } else if (self.options.changeMode == "point") {
  196. self.pointmoveDrag(obj);
  197. }
  198. }else{
  199. self.moveAddClass(obj);
  200. }*/
  201. if(self.options.pos==true){
  202. self.moveAddClass(obj);
  203. }
  204. self.options.cbMove(obj,self);
  205. },
  206. end: function (ev, obj) {
  207. var self = this;
  208. if (self._start != true) {
  209. return false
  210. }
  211. if(self.options.changeMode=="sort"&&self.options.pos==true){
  212. self.sortDrag(obj);
  213. }else if(self.options.changeMode=="point"&&self.options.pos==true){
  214. self.pointDrag(obj);
  215. }
  216. if(self.options.pos==true){
  217. self.animation(obj, self.aPos[$(obj).attr("index")]);
  218. }
  219. self.options.cbEnd();
  220. if(self.options.handle!=null){
  221. $(obj).find(self.options.handle).unbind("onmousemove");
  222. $(obj).find(self.options.handle).unbind("onmouseup");
  223. }else{
  224. $(obj).unbind("onmousemove");
  225. $(obj).unbind("onmouseup");
  226. }
  227. obj.releaseCapture && obj.releaseCapture();
  228. self._start = false;
  229. },
  230. //算父级的宽高
  231. collTestBox: function (obj, obj2) {
  232. var self = this;
  233. var l1 = 0;
  234. var t1 = 0;
  235. var l2 = $(obj2).innerWidth() - $(obj).outerWidth();
  236. var t2 = $(obj2).innerHeight() - $(obj).outerHeight();
  237. return {
  238. lmin: l1,//取的l最小值
  239. tmin: t1,//取的t最小值
  240. lmax: l2,//取的l最大值
  241. tmax: t2//取的t最大值
  242. }
  243. },
  244. //算父级宽高时候干掉margin
  245. grid: function (obj, l, t) {//cur:[width,height]
  246. var self = this;
  247. var json = {
  248. left: l,
  249. top: t
  250. };
  251. if ($.isArray(self.options.grid) && self.options.grid.length == 2) {
  252. var gx = self.options.grid[0];
  253. var gy = self.options.grid[1];
  254. json.left = Math.floor((l + gx / 2) / gx) * gx;
  255. json.top = Math.floor((t + gy / 2) / gy) * gy;
  256. return json
  257. } else if (self.options.grid == null) {
  258. return json
  259. } else {
  260. console.log("grid参数传递格式错误");
  261. return false
  262. }
  263. },
  264. findNearest: function(obj){
  265. var self=this;
  266. var iMin=new Date().getTime();
  267. var iMinIndex=-1;
  268. var ele=self.ele;
  269. for(var i=0;i<ele.length;i++){
  270. if(obj==ele[i]){
  271. continue;
  272. }
  273. if(self.collTest(obj,ele[i])){
  274. var dis=self.getDis(obj,ele[i]);
  275. if(dis<iMin){
  276. iMin=dis;
  277. iMinIndex=i;
  278. }
  279. }
  280. }
  281. if(iMinIndex==-1){
  282. return null;
  283. }else{
  284. return ele[iMinIndex];
  285. }
  286. },
  287. getDis: function(obj,obj2){
  288. var self=this;
  289. var l1=obj.offsetLeft+obj.offsetWidth/2;
  290. var l2=obj2.offsetLeft+obj2.offsetWidth/2;
  291. var t1=obj.offsetTop+obj.offsetHeight/2;
  292. var t2=obj2.offsetTop+obj2.offsetHeight/2;
  293. var a=l2-l1;
  294. var b=t1-t2;
  295. return Math.sqrt(a*a+b*b);
  296. },
  297. collTest: function(obj,obj2){
  298. var self=this;
  299. var l1=obj.offsetLeft;
  300. var r1=obj.offsetLeft+obj.offsetWidth;
  301. var t1=obj.offsetTop;
  302. var b1=obj.offsetTop+obj.offsetHeight;
  303. var l2=obj2.offsetLeft;
  304. var r2=obj2.offsetLeft+obj2.offsetWidth;
  305. var t2=obj2.offsetTop;
  306. var b2=obj2.offsetTop+obj2.offsetHeight;
  307. if(r1<l2 || r2<l1 || t2>b1 || b2<t1){
  308. return false;
  309. }else{
  310. return true;
  311. }
  312. },
  313. //初始布局转换
  314. pack: function(ele,click){
  315. var self=this;
  316. self.toDisable();
  317. if(self.options.pos==false){
  318. for (var i = 0; i < ele.length; i++) {
  319. $(ele[i]).css("position", "absolute");
  320. $(ele[i]).css("margin", "0");
  321. self.init(ele[i]);
  322. }
  323. }else if(self.options.pos==true) {
  324. var arr = [];
  325. if (self.options.random || click) {
  326. while (arr.length < ele.length) {
  327. var n = self.rnd(0, ele.length);
  328. if (!self.finInArr(arr, n)) {//没找到
  329. arr.push(n);
  330. }
  331. }
  332. }
  333. if (self.options.random == false || click != true) {
  334. var n = 0;
  335. while (arr.length < ele.length) {
  336. arr.push(n);
  337. n++
  338. }
  339. }
  340. //如果是第二次以后随机列表,那就重新排序后再随机,因为我智商不够使,不会排了
  341. if (self.firstRandom == false) {
  342. var sortarr = [];
  343. var n = 0;
  344. while (sortarr.length < ele.length) {
  345. sortarr.push(n);
  346. n++
  347. }
  348. for (var i = 0; i < ele.length; i++) {
  349. $(ele[i]).attr("index", sortarr[i]);
  350. $(ele[i]).css("left", self.aPos[sortarr[i]].left);
  351. $(ele[i]).css("top", self.aPos[sortarr[i]].top);
  352. }
  353. }
  354. //布局转化
  355. self.aPos = [];
  356. if (self.firstRandom == false) {
  357. //不是第一次
  358. for (var j = 0; j < ele.length; j++) {
  359. self.aPos[j] = {
  360. left: ele[$(ele).eq(j).attr("index")].offsetLeft,
  361. top: ele[$(ele).eq(j).attr("index")].offsetTop
  362. };
  363. }
  364. } else {
  365. //第一次
  366. for (var j = 0; j < ele.length; j++) {
  367. self.aPos[j] = {left: ele[j].offsetLeft, top: ele[j].offsetTop};
  368. }
  369. }
  370. //第二个循环布局转化
  371. for (var i = 0; i < ele.length; i++) {
  372. $(ele[i]).attr("index", arr[i]);
  373. $(ele[i]).css("left", self.aPos[arr[i]].left);
  374. $(ele[i]).css("top", self.aPos[arr[i]].top);
  375. $(ele[i]).css("position", "absolute");
  376. $(ele[i]).css("margin", "0");
  377. self.init(ele[i]);
  378. }
  379. self.firstRandom = false;
  380. }
  381. },
  382. //移动时候加class
  383. moveAddClass: function(obj){
  384. var self=this;
  385. var oNear=self.findNearest(obj);
  386. $(self.$element).removeClass(self.options.moveClass);
  387. if(oNear && $(oNear).hasClass(self.options.moveClass)==false){
  388. $(oNear).addClass(self.options.moveClass);
  389. }
  390. },
  391. //给li排序
  392. sort: function(){
  393. var self=this;
  394. var arr_li=[];
  395. for (var s = 0; s < self.$element.length; s++) {
  396. arr_li.push(self.$element[s]);
  397. }
  398. for ( var i = 0; i < arr_li.length; i++) {
  399. for ( var j = i + 1; j < arr_li.length; j++) {
  400. if(Number($(arr_li[i]).attr("index")) > Number($(arr_li[j]).attr("index"))){
  401. var temp = arr_li[i];
  402. arr_li[i] = arr_li[j];
  403. arr_li[j] = temp;
  404. }
  405. }
  406. }
  407. return arr_li;
  408. },
  409. //点对点的方式换位
  410. pointDrag: function(obj){
  411. var self=this;
  412. //先拍序
  413. var oNear=self.findNearest(obj);
  414. if (oNear) {
  415. self.animation(obj,self.aPos[$(oNear).attr("index")]);
  416. self.animation(oNear, self.aPos[$(obj).attr("index")]);
  417. var tmp;
  418. tmp = $(obj).attr("index");
  419. $(obj).attr("index", $(oNear).attr("index"));
  420. $(oNear).attr("index", tmp);
  421. $(oNear).removeClass(self.options.moveClass);
  422. } else if (self.options.changeWhen == "end") {
  423. self.animation(obj, self.aPos[$(obj).attr("index")]);
  424. }
  425. },
  426. //排序的方式换位
  427. sortDrag: function(obj){
  428. var self=this;
  429. //先拍序
  430. var arr_li=self.sort();
  431. //换位置
  432. var oNear=self.findNearest(obj);
  433. if(oNear){
  434. if(Number($(oNear).attr("index"))>Number($(obj).attr("index"))){
  435. //前换后
  436. var obj_tmp=Number($(obj).attr("index"));
  437. $(obj).attr("index",Number($(oNear).attr("index"))+1);
  438. for (var i = obj_tmp; i < Number($(oNear).attr("index"))+1; i++) {
  439. self.animation(arr_li[i],self.aPos[i-1]);
  440. self.animation(obj,self.aPos[$(oNear).attr("index")]);
  441. $(arr_li[i]).removeClass(self.options.moveClass);
  442. $(arr_li[i]).attr("index",Number($(arr_li[i]).attr("index"))-1);
  443. }
  444. }else if(Number($(obj).attr("index"))>Number($(oNear).attr("index"))){
  445. //后换前
  446. var obj_tmp=Number($(obj).attr("index"));
  447. $(obj).attr("index",$(oNear).attr("index"));
  448. for (var i = Number($(oNear).attr("index")); i < obj_tmp; i++) {
  449. self.animation(arr_li[i],self.aPos[i+1]);
  450. self.animation(obj,self.aPos[Number($(obj).attr("index"))]);
  451. $(arr_li[i]).removeClass(self.options.moveClass);
  452. $(arr_li[i]).attr("index",Number($(arr_li[i]).attr("index"))+1);
  453. }
  454. }
  455. }else{
  456. self.animation(obj,self.aPos[$(obj).attr("index")]);
  457. }
  458. },
  459. //运动函数(后期再加参数)
  460. animation: function(obj,json){
  461. var self=this;
  462. //考虑默认值
  463. var options=self.options.animation_options; /*|| {};
  464. options.duration=self.options.animation_options.duration || 800;
  465. options.easing=options.easing.duration.easing || 'ease-out';*/
  466. var self=this;
  467. var count=Math.round(options.duration/30);
  468. var start={};
  469. var dis={};
  470. for(var name in json){
  471. start[name]=parseFloat(self.getStyle(obj,name));
  472. if(isNaN(start[name])){
  473. switch(name){
  474. case 'left':
  475. start[name]=obj.offsetLeft;
  476. break;
  477. case 'top':
  478. start[name]=obj.offsetTop;
  479. break;
  480. case 'width':
  481. start[name]=obj.offsetWidth;
  482. break;
  483. case 'height':
  484. start[name]=obj.offsetHeight;
  485. break;
  486. case 'marginLeft':
  487. start[name]=obj.offsetLeft;
  488. break;
  489. case 'borderWidth':
  490. start[name]=0;
  491. break;
  492. //...
  493. }
  494. }
  495. dis[name]=json[name]-start[name];
  496. }
  497. var n=0;
  498. clearInterval(obj.timer);
  499. obj.timer=setInterval(function(){
  500. n++;
  501. for(var name in json){
  502. switch(options.easing){
  503. case 'linear':
  504. var a=n/count;
  505. var cur=start[name]+dis[name]*a;
  506. break;
  507. case 'ease-in':
  508. var a=n/count;
  509. var cur=start[name]+dis[name]*a*a*a;
  510. break;
  511. case 'ease-out':
  512. var a=1-n/count;
  513. var cur=start[name]+dis[name]*(1-a*a*a);
  514. break;
  515. }
  516. if(name=='opacity'){
  517. obj.style.opacity=cur;
  518. obj.style.filter='alpha(opacity:'+cur*100+')';
  519. }else{
  520. obj.style[name]=cur+'px';
  521. }
  522. }
  523. if(n==count){
  524. clearInterval(obj.timer);
  525. options.complete && options.complete();
  526. }
  527. },30);
  528. },
  529. getStyle: function(obj,name){
  530. return (obj.currentStyle || getComputedStyle(obj,false))[name];
  531. },
  532. //随机数
  533. rnd: function(n,m){
  534. return parseInt(Math.random()*(m-n)+n);
  535. },
  536. //在数组中找
  537. finInArr: function(arr,n){
  538. for(var i = 0 ; i < arr.length; i++){
  539. if(arr[i] == n){//存在
  540. return true;
  541. }
  542. }
  543. return false;
  544. }
  545. }
  546. })
  547. })(jQuery,window,document);