tdrag.js 26 KB

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