vue-draggable-resizable
Version:
Vue3 Component for resizable and draggable elements
2 lines (1 loc) • 15.8 kB
JavaScript
(function(w,l){typeof exports=="object"&&typeof module<"u"?l(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],l):(w=typeof globalThis<"u"?globalThis:w||self,l(w.VueDraggableResizable={},w.Vue))})(this,function(w,l){"use strict";const X="";function v(t){return typeof t=="function"||Object.prototype.toString.call(t)==="[object Function]"}function z(t,e,i,s=1){const[o,h]=typeof s=="number"?[s,s]:s,a=Math.round(e/o/t[0])*t[0],r=Math.round(i/h/t[1])*t[1];return[a,r]}function M(t,e,i){return t-e-i}function H(t,e,i){return t-e-i}function g(t,e,i){return e!==null&&t<e?e:i!==null&&i<t?i:t}function B(t,e,i){let s=t;const o=["matches","webkitMatchesSelector","mozMatchesSelector","msMatchesSelector","oMatchesSelector"].find(h=>v(s[h]));if(!v(s[o]))return!1;do{if(s[o](e))return!0;if(s===i)return!1;s=s.parentNode}while(s);return!1}function k(t){const e=window.getComputedStyle(t);return[parseFloat(e.getPropertyValue("width"),10),parseFloat(e.getPropertyValue("height"),10)]}function y(t,e,i){t&&(t.attachEvent?t.attachEvent("on"+e,i):t.addEventListener?t.addEventListener(e,i,!0):t["on"+e]=i)}function p(t,e,i){t&&(t.detachEvent?t.detachEvent("on"+e,i):t.removeEventListener?t.removeEventListener(e,i,!0):t["on"+e]=null)}const D=(t,e)=>{const i=t.__vccOpts||t;for(const[s,o]of e)i[s]=o;return i},x={mouse:{start:"mousedown",move:"mousemove",stop:"mouseup"},touch:{start:"touchstart",move:"touchmove",stop:"touchend"}},E={userSelect:"none",MozUserSelect:"none",WebkitUserSelect:"none",MsUserSelect:"none"},W={userSelect:"auto",MozUserSelect:"auto",WebkitUserSelect:"auto",MsUserSelect:"auto"};let b=x.mouse;const L={replace:!0,name:"vue-draggable-resizable",props:{className:{type:String,default:"vdr"},classNameDraggable:{type:String,default:"draggable"},classNameResizable:{type:String,default:"resizable"},classNameDragging:{type:String,default:"dragging"},classNameResizing:{type:String,default:"resizing"},classNameActive:{type:String,default:"active"},classNameHandle:{type:String,default:"handle"},disableUserSelect:{type:Boolean,default:!0},enableNativeDrag:{type:Boolean,default:!1},preventDeactivation:{type:Boolean,default:!1},active:{type:Boolean,default:!1},draggable:{type:Boolean,default:!0},resizable:{type:Boolean,default:!0},lockAspectRatio:{type:Boolean,default:!1},w:{type:[Number,String],default:200,validator:t=>typeof t=="number"?t>0:t==="auto"},h:{type:[Number,String],default:200,validator:t=>typeof t=="number"?t>0:t==="auto"},minWidth:{type:Number,default:0,validator:t=>t>=0},minHeight:{type:Number,default:0,validator:t=>t>=0},maxWidth:{type:Number,default:null,validator:t=>t>=0},maxHeight:{type:Number,default:null,validator:t=>t>=0},x:{type:Number,default:0},y:{type:Number,default:0},z:{type:[String,Number],default:"auto",validator:t=>typeof t=="string"?t==="auto":t>=0},handles:{type:Array,default:()=>["tl","tm","tr","mr","br","bm","bl","ml"],validator:t=>{const e=new Set(["tl","tm","tr","mr","br","bm","bl","ml"]);return new Set(t.filter(i=>e.has(i))).size===t.length}},dragHandle:{type:String,default:null},dragCancel:{type:String,default:null},axis:{type:String,default:"both",validator:t=>["x","y","both"].includes(t)},grid:{type:Array,default:()=>[1,1]},parent:{type:Boolean,default:!1},scale:{type:[Number,Array],default:1,validator:t=>typeof t=="number"?t>0:t.length===2&&t[0]>0&&t[1]>0},onDragStart:{type:Function,default:()=>!0},onDrag:{type:Function,default:()=>!0},onResizeStart:{type:Function,default:()=>!0},onResize:{type:Function,default:()=>!0}},data:function(){return{left:this.x,top:this.y,right:null,bottom:null,width:null,height:null,widthTouched:!1,heightTouched:!1,aspectFactor:null,parentWidth:null,parentHeight:null,handle:null,enabled:this.active,resizing:!1,dragging:!1,dragEnable:!1,resizeEnable:!1,zIndex:this.z}},created:function(){this.maxWidth&&this.minWidth>this.maxWidth&&console.warn("[Vdr warn]: Invalid prop: minWidth cannot be greater than maxWidth"),this.maxHeight&&this.minHeight>this.maxHeight&&console.warn("[Vdr warn]: Invalid prop: minHeight cannot be greater than maxHeight"),this.resetBoundsAndMouseState()},mounted:function(){this.enableNativeDrag||(this.$el.ondragstart=()=>!1);const[t,e]=this.getParentSize();this.parentWidth=t,this.parentHeight=e;const[i,s]=k(this.$el);this.aspectFactor=(this.w!=="auto"?this.w:i)/(this.h!=="auto"?this.h:s),this.width=this.w!=="auto"?this.w:i,this.height=this.h!=="auto"?this.h:s,this.right=this.parentWidth-this.width-this.left,this.bottom=this.parentHeight-this.height-this.top,this.active&&this.$emit("activated"),y(document.documentElement,"mousedown",this.deselect),y(document.documentElement,"touchend touchcancel",this.deselect),y(window,"resize",this.checkParentSize)},beforeUnmount:function(){p(document.documentElement,"mousedown",this.deselect),p(document.documentElement,"touchstart",this.handleUp),p(document.documentElement,"mousemove",this.move),p(document.documentElement,"touchmove",this.move),p(document.documentElement,"mouseup",this.handleUp),p(document.documentElement,"touchend touchcancel",this.deselect),p(window,"resize",this.checkParentSize)},methods:{resetBoundsAndMouseState(){this.mouseClickPosition={mouseX:0,mouseY:0,x:0,y:0,w:0,h:0},this.bounds={minLeft:null,maxLeft:null,minRight:null,maxRight:null,minTop:null,maxTop:null,minBottom:null,maxBottom:null}},checkParentSize(){if(this.parent){const[t,e]=this.getParentSize();this.parentWidth=t,this.parentHeight=e,this.right=this.parentWidth-this.width-this.left,this.bottom=this.parentHeight-this.height-this.top}},getParentSize(){if(this.parent){const t=window.getComputedStyle(this.$el.parentNode,null);return[parseInt(t.getPropertyValue("width"),10),parseInt(t.getPropertyValue("height"),10)]}return[null,null]},elementTouchDown(t){b=x.touch,this.elementDown(t)},elementMouseDown(t){b=x.mouse,this.elementDown(t)},elementDown(t){if(t instanceof MouseEvent&&t.button!==0)return;const e=t.target||t.srcElement;if(this.$el.contains(e)){if(this.onDragStart(t)===!1)return;if(this.dragHandle&&!B(e,this.dragHandle,this.$el)||this.dragCancel&&B(e,this.dragCancel,this.$el)){this.dragging=!1;return}this.enabled||(this.enabled=!0,this.$emit("activated"),this.$emit("update:active",!0)),this.draggable&&(this.dragEnable=!0),this.mouseClickPosition.mouseX=t.touches?t.touches[0].pageX:t.pageX,this.mouseClickPosition.mouseY=t.touches?t.touches[0].pageY:t.pageY,this.mouseClickPosition.left=this.left,this.mouseClickPosition.right=this.right,this.mouseClickPosition.top=this.top,this.mouseClickPosition.bottom=this.bottom,this.parent&&(this.bounds=this.calcDragLimits()),y(document.documentElement,b.move,this.move),y(document.documentElement,b.stop,this.handleUp)}},calcDragLimits(){return{minLeft:this.left%this.grid[0],maxLeft:Math.floor((this.parentWidth-this.width-this.left)/this.grid[0])*this.grid[0]+this.left,minRight:this.right%this.grid[0],maxRight:Math.floor((this.parentWidth-this.width-this.right)/this.grid[0])*this.grid[0]+this.right,minTop:this.top%this.grid[1],maxTop:Math.floor((this.parentHeight-this.height-this.top)/this.grid[1])*this.grid[1]+this.top,minBottom:this.bottom%this.grid[1],maxBottom:Math.floor((this.parentHeight-this.height-this.bottom)/this.grid[1])*this.grid[1]+this.bottom}},deselect(t){const e=t.target||t.srcElement,i=new RegExp(this.className+"-([trmbl]{2})","");!this.$el.contains(e)&&!i.test(e.className)&&(this.enabled&&!this.preventDeactivation&&(this.enabled=!1,this.$emit("deactivated"),this.$emit("update:active",!1)),p(document.documentElement,b.move,this.handleResize)),this.resetBoundsAndMouseState()},handleTouchDown(t,e){b=x.touch,this.handleDown(t,e)},handleDown(t,e){e instanceof MouseEvent&&e.which!==1||this.onResizeStart(t,e)!==!1&&(e.stopPropagation&&e.stopPropagation(),this.lockAspectRatio&&!t.includes("m")?this.handle="m"+t.substring(1):this.handle=t,this.resizeEnable=!0,this.mouseClickPosition.mouseX=e.touches?e.touches[0].pageX:e.pageX,this.mouseClickPosition.mouseY=e.touches?e.touches[0].pageY:e.pageY,this.mouseClickPosition.left=this.left,this.mouseClickPosition.right=this.right,this.mouseClickPosition.top=this.top,this.mouseClickPosition.bottom=this.bottom,this.bounds=this.calcResizeLimits(),y(document.documentElement,b.move,this.handleResize),y(document.documentElement,b.stop,this.handleUp))},calcResizeLimits(){let t=this.minW,e=this.minH,i=this.maxW,s=this.maxH;const o=this.aspectFactor,[h,a]=this.grid,r=this.width,f=this.height,u=this.left,m=this.top,d=this.right,c=this.bottom;this.lockAspectRatio&&(t/e>o?e=t/o:t=o*e,i&&s?(i=Math.min(i,o*s),s=Math.min(s,i/o)):i?s=i/o:s&&(i=o*s)),i=i-i%h,s=s-s%a;const n={minLeft:null,maxLeft:null,minTop:null,maxTop:null,minRight:null,maxRight:null,minBottom:null,maxBottom:null};return this.parent?(n.minLeft=u%h,n.maxLeft=u+Math.floor((r-t)/h)*h,n.minTop=m%a,n.maxTop=m+Math.floor((f-e)/a)*a,n.minRight=d%h,n.maxRight=d+Math.floor((r-t)/h)*h,n.minBottom=c%a,n.maxBottom=c+Math.floor((f-e)/a)*a,i&&(n.minLeft=Math.max(n.minLeft,this.parentWidth-d-i),n.minRight=Math.max(n.minRight,this.parentWidth-u-i)),s&&(n.minTop=Math.max(n.minTop,this.parentHeight-c-s),n.minBottom=Math.max(n.minBottom,this.parentHeight-m-s)),this.lockAspectRatio&&(n.minLeft=Math.max(n.minLeft,u-m*o),n.minTop=Math.max(n.minTop,m-u/o),n.minRight=Math.max(n.minRight,d-c*o),n.minBottom=Math.max(n.minBottom,c-d/o))):(n.minLeft=null,n.maxLeft=u+Math.floor((r-t)/h)*h,n.minTop=null,n.maxTop=m+Math.floor((f-e)/a)*a,n.minRight=null,n.maxRight=d+Math.floor((r-t)/h)*h,n.minBottom=null,n.maxBottom=c+Math.floor((f-e)/a)*a,i&&(n.minLeft=-(d+i),n.minRight=-(u+i)),s&&(n.minTop=-(c+s),n.minBottom=-(m+s)),this.lockAspectRatio&&i&&s&&(n.minLeft=Math.min(n.minLeft,-(d+i)),n.minTop=Math.min(n.minTop,-(s+c)),n.minRight=Math.min(n.minRight,-u-i),n.minBottom=Math.min(n.minBottom,-m-s))),n},move(t){this.resizing?this.handleResize(t):this.dragEnable&&this.handleDrag(t)},handleDrag(t){const e=this.axis,i=this.grid,s=this.bounds,o=this.mouseClickPosition,h=e&&e!=="y"?o.mouseX-(t.touches?t.touches[0].pageX:t.pageX):0,a=e&&e!=="x"?o.mouseY-(t.touches?t.touches[0].pageY:t.pageY):0,[r,f]=z(i,h,a,this.scale),u=g(o.left-r,s.minLeft,s.maxLeft),m=g(o.top-f,s.minTop,s.maxTop);if(this.onDrag(u,m)===!1)return;const d=g(o.right+r,s.minRight,s.maxRight),c=g(o.bottom+f,s.minBottom,s.maxBottom);this.left=u,this.top=m,this.right=d,this.bottom=c,this.$emit("dragging",this.left,this.top),this.dragging=!0},moveHorizontally(t){const[e,i]=z(this.grid,t,this.top,1),s=g(e,this.bounds.minLeft,this.bounds.maxLeft);this.left=s,this.right=this.parentWidth-this.width-s},moveVertically(t){const[e,i]=z(this.grid,this.left,t,1),s=g(i,this.bounds.minTop,this.bounds.maxTop);this.top=s,this.bottom=this.parentHeight-this.height-s},handleResize(t){let e=this.left,i=this.top,s=this.right,o=this.bottom;const h=this.mouseClickPosition,a=this.aspectFactor,r=h.mouseX-(t.touches?t.touches[0].pageX:t.pageX),f=h.mouseY-(t.touches?t.touches[0].pageY:t.pageY);!this.widthTouched&&r&&(this.widthTouched=!0),!this.heightTouched&&f&&(this.heightTouched=!0);const[u,m]=z(this.grid,r,f,this.scale);this.handle.includes("b")?(o=g(h.bottom+m,this.bounds.minBottom,this.bounds.maxBottom),this.lockAspectRatio&&this.resizingOnY&&(s=this.right-(this.bottom-o)*a)):this.handle.includes("t")&&(i=g(h.top-m,this.bounds.minTop,this.bounds.maxTop),this.lockAspectRatio&&this.resizingOnY&&(e=this.left-(this.top-i)*a)),this.handle.includes("r")?(s=g(h.right+u,this.bounds.minRight,this.bounds.maxRight),this.lockAspectRatio&&this.resizingOnX&&(o=this.bottom-(this.right-s)/a)):this.handle.includes("l")&&(e=g(h.left-u,this.bounds.minLeft,this.bounds.maxLeft),this.lockAspectRatio&&this.resizingOnX&&(i=this.top-(this.left-e)/a));const d=M(this.parentWidth,e,s),c=H(this.parentHeight,i,o);this.onResize(this.handle,e,i,d,c)!==!1&&(this.left=e,this.top=i,this.right=s,this.bottom=o,this.width=d,this.height=c,this.$emit("resizing",this.left,this.top,this.width,this.height),this.resizing=!0)},changeWidth(t){const[e,i]=z(this.grid,t,0,1),s=g(this.parentWidth-e-this.left,this.bounds.minRight,this.bounds.maxRight);let o=this.bottom;this.lockAspectRatio&&(o=this.bottom-(this.right-s)/this.aspectFactor);const h=M(this.parentWidth,this.left,s),a=H(this.parentHeight,this.top,o);this.right=s,this.bottom=o,this.width=h,this.height=a},changeHeight(t){const[e,i]=z(this.grid,0,t,1),s=g(this.parentHeight-i-this.top,this.bounds.minBottom,this.bounds.maxBottom);let o=this.right;this.lockAspectRatio&&(o=this.right-(this.bottom-s)*this.aspectFactor);const h=M(this.parentWidth,this.left,o),a=H(this.parentHeight,this.top,s);this.right=o,this.bottom=s,this.width=h,this.height=a},handleUp(t){this.handle=null,this.resetBoundsAndMouseState(),this.dragEnable=!1,this.resizeEnable=!1,this.resizing&&(this.resizing=!1,this.$emit("resizeStop",this.left,this.top,this.width,this.height)),this.dragging&&(this.dragging=!1,this.$emit("dragStop",this.left,this.top)),p(document.documentElement,b.move,this.handleResize)}},computed:{style(){return{transform:`translate(${this.left}px, ${this.top}px)`,width:this.computedWidth,height:this.computedHeight,zIndex:this.zIndex,...this.dragging&&this.disableUserSelect?E:W}},actualHandles(){return this.resizable?this.handles:[]},computedWidth(){return this.w==="auto"&&!this.widthTouched?"auto":this.width+"px"},computedHeight(){return this.h==="auto"&&!this.heightTouched?"auto":this.height+"px"},minW(){return this.minWidth},minH(){return this.minHeight},maxW(){return this.maxWidth},maxH(){return this.maxHeight},resizingOnX(){return!!this.handle&&(this.handle.includes("l")||this.handle.includes("r"))},resizingOnY(){return!!this.handle&&(this.handle.includes("t")||this.handle.includes("b"))},isCornerHandle(){return!!this.handle&&["tl","tr","br","bl"].includes(this.handle)}},watch:{active(t){this.enabled=t,t?this.$emit("activated"):this.$emit("deactivated")},z(t){(t>=0||t==="auto")&&(this.zIndex=t)},x(t){this.resizing||this.dragging||(this.parent&&(this.bounds=this.calcDragLimits()),this.moveHorizontally(t))},y(t){this.resizing||this.dragging||(this.parent&&(this.bounds=this.calcDragLimits()),this.moveVertically(t))},lockAspectRatio(t){t?this.aspectFactor=this.width/this.height:this.aspectFactor=void 0},w(t){this.resizing||this.dragging||(this.parent&&(this.bounds=this.calcResizeLimits()),this.changeWidth(t))},h(t){this.resizing||this.dragging||(this.parent&&(this.bounds=this.calcResizeLimits()),this.changeHeight(t))}}},P=["onMousedown","onTouchstart"];function N(t,e,i,s,o,h){return l.openBlock(),l.createElementBlock("div",{style:l.normalizeStyle(h.style),class:l.normalizeClass([{[i.classNameActive]:t.enabled,[i.classNameDragging]:t.dragging,[i.classNameResizing]:t.resizing,[i.classNameDraggable]:i.draggable,[i.classNameResizable]:i.resizable},i.className]),onMousedown:e[0]||(e[0]=(...a)=>h.elementMouseDown&&h.elementMouseDown(...a)),onTouchstart:e[1]||(e[1]=(...a)=>h.elementTouchDown&&h.elementTouchDown(...a))},[(l.openBlock(!0),l.createElementBlock(l.Fragment,null,l.renderList(h.actualHandles,a=>(l.openBlock(),l.createElementBlock("div",{key:a,class:l.normalizeClass([i.classNameHandle,i.classNameHandle+"-"+a]),style:l.normalizeStyle({display:t.enabled?"block":"none"}),onMousedown:l.withModifiers(r=>h.handleDown(a,r),["stop","prevent"]),onTouchstart:l.withModifiers(r=>h.handleTouchDown(a,r),["stop","prevent"])},[l.renderSlot(t.$slots,a)],46,P))),128)),l.renderSlot(t.$slots,"default")],38)}const T=D(L,[["render",N]]);function S(t){S.installed||(S.installed=!0,t.component("VueDraggableResizable",T))}const C={install:S};let R=null;typeof window<"u"?R=window.Vue:typeof global<"u"&&(R=global.Vue),R&&R.use(C),w.default=T,w.install=S,Object.defineProperties(w,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});