UNPKG

vue-grabbing-box

Version:

vue-grabbing-box is a container component that allows you to grab to change view-box and also with scaling

6 lines (5 loc) 11.4 kB
(function(g,a){typeof exports=="object"&&typeof module<"u"?a(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],a):(g=typeof globalThis<"u"?globalThis:g||self,a(g.GrabbingBox={},g.Vue))})(this,function(g,a){"use strict";var v=document.createElement("style");v.textContent=`.relative{position:relative}.flex{display:flex}.h-full{height:100%}.w-full{width:100%}.cursor-grab{cursor:grab}.cursor-grabbing{cursor:grabbing}.flex-col{flex-direction:column}.overflow-hidden{overflow:hidden}.items-center{align-items:center}.justify-center{justify-content:center}.scale-btn-group[data-v-a9729596]{position:absolute;top:20px;right:10px;z-index:999;user-select:none}.scale-button[data-v-a9729596]{height:28px;text-align:center;color:#606266;background:#fff;border:1px solid #dcdfe6;cursor:pointer;box-sizing:border-box;vertical-align:middle;outline:none}.scale-button[data-v-a9729596]:hover:not(.is-disabled){color:#409eff;border-color:#c6e2ff;background-color:#ecf5ff}.scale-button[data-v-a9729596]:active:not(.is-disabled){color:#3a8ee6;border-color:#3a8ee6;outline:0}.scale-button.is-disabled[data-v-a9729596]{color:#c0c4cc;cursor:not-allowed;background-image:none;background-color:#fff;border-color:#ebeef5}.scale-button.btn-plus[data-v-a9729596],.scale-button.btn-minus[data-v-a9729596]{width:28px;font-size:1.25rem;border-radius:50%;line-height:24px}.scale-button.btn-reset[data-v-a9729596]{padding:5px 15px;font-size:12px;border-radius:2px;margin-left:10px}.grabbing-box-container .cursor-grab[data-v-58cc9f3c],.grabbing-box-container .cursor-grab *[data-v-58cc9f3c] :not(:hover){cursor:grab}.grabbing-box-container .cursor-grabbing[data-v-58cc9f3c],.grabbing-box-container .cursor-grabbing *[data-v-58cc9f3c]{cursor:grabbing}.grabbing-box-container .scale-button-group[data-v-58cc9f3c]{--scale-buttons-space-x: 10px;--scale-buttons-space-y: 20px}.grabbing-box-container .scale-button-group.custom-position-top[data-v-58cc9f3c]{top:var(--scale-buttons-space-y);bottom:unset}.grabbing-box-container .scale-button-group.custom-position-bottom[data-v-58cc9f3c]{bottom:var(--scale-buttons-space-y);top:unset}.grabbing-box-container .scale-button-group.custom-position-left[data-v-58cc9f3c]{left:var(--scale-buttons-space-x);right:unset}.grabbing-box-container .scale-button-group.custom-position-right[data-v-58cc9f3c]{right:var(--scale-buttons-space-x);left:unset}.grabbing-box-container .grabbing-box *[data-v-58cc9f3c]{-webkit-user-drag:none} `,document.head.appendChild(v);const ot="",I="1.0.0";function D(){const l=navigator.userAgent;return!["Android","iPhone","SymbianOS","Windows Phone","iPad","iPod"].some(n=>l.includes(n))}function V(l,f=50){let n=0;return function(...u){if(typeof l!="function")throw new Error(`${l} is not a function`);const i=this;if(!(Date.now()-n<f))return n=Date.now(),l.apply(i,u)}}const nt="",T=(l,f)=>{const n=l.__vccOpts||l;for(const[u,i]of f)n[u]=i;return n},w=l=>(a.pushScopeId("data-v-a9729596"),l=l(),a.popScopeId(),l),j={class:"scale-btn-group flex items-center"},$=["onClick"],H=[w(()=>a.createElementVNode("svg",{xmlns:"http://www.w3.org/2000/svg",width:"20",height:"20",viewBox:"0 0 24 24"},[a.createElementVNode("path",{fill:"currentColor",d:"M18 12.998h-5v5a1 1 0 0 1-2 0v-5H6a1 1 0 0 1 0-2h5v-5a1 1 0 0 1 2 0v5h5a1 1 0 0 1 0 2z"})],-1))],L={style:{display:"inline-block",margin:"0 8px"}},R=["onClick"],W=[w(()=>a.createElementVNode("svg",{xmlns:"http://www.w3.org/2000/svg",width:"20",height:"20",viewBox:"0 0 24 24"},[a.createElementVNode("path",{fill:"currentColor",d:"M18 12.998H6a1 1 0 0 1 0-2h12a1 1 0 0 1 0 2z"})],-1))],G=["onClick"],q=T({__name:"index",props:{scaling:{type:Number,default:100},maxScale:{type:Number,default:200},minScale:{type:Number,default:20}},emits:["zoom-in","zoom-out","reset"],setup(l,{emit:f}){const n=l,u=a.computed(()=>n.scaling>=n.maxScale),i=a.computed(()=>n.scaling<=n.minScale),e=()=>{f("zoom-in")},y=()=>{f("zoom-out")},h=()=>{f("reset")};return(B,k)=>(a.openBlock(),a.createElementBlock("div",j,[a.createElementVNode("div",{class:a.normalizeClass(["scale-button btn-plus flex justify-center items-center",{"is-disabled":a.unref(u)}]),onClick:a.withModifiers(e,["stop"])},H,10,$),a.createElementVNode("div",L,a.toDisplayString(l.scaling)+"%",1),a.createElementVNode("div",{class:a.normalizeClass(["scale-button btn-minus flex justify-center items-center",{"is-disabled":a.unref(i)}]),onClick:a.withModifiers(y,["stop"])},W,10,R),a.createElementVNode("div",{class:"scale-button btn-reset",onClick:a.withModifiers(h,["stop"])},"重置",8,G)]))}},[["__scopeId","data-v-a9729596"]]),lt="",b=T(Object.assign({data(){return{}}},{__name:"grabbing-box",props:{useCapture:{type:Boolean,default:!0},maxScale:{type:Number,default:200},minScale:{type:Number,default:20},initScale:{type:Number,default:100},scaleButtons:{type:Boolean,default:!0},scaleButtonsPosition:{type:String,default:"top right"},scaleButtonsSpaceX:{type:String,default:"10px"},scaleButtonsSpaceY:{type:String,default:"20px"},scaleStep:{type:Number,default:10},throttleSpan:{type:Number,default:50},emitClickOnDrag:{type:Boolean,default:!1}},emits:["zoom-in","zoom-out","reset","move","update"],setup(l,{emit:f}){const n=l,u=a.ref(null),i=a.ref(null),e=a.reactive({lastTransformData:{scale:1,translateX:0,translateY:0},lastPosition:{x:null,y:null,distance:0},readyToDrag:!1,readyToScale:!1,dragging:!1,isScaling:!1,scaleTranslateProportion:[0,0],dragged:!1}),y=a.computed(()=>{const{scale:t}=e.lastTransformData;return parseInt(t*1e4/100)}),h=a.computed(()=>{const t=(n.scaleButtonsPosition||"").trim().toLowerCase();if(!t)return{right:!0,top:!0,left:!1,bottom:!1};const o=t.includes("left")?"left":"right",s=t.includes("bottom")?"bottom":"top";return{top:s==="top",bottom:s==="bottom",left:o==="left",right:o==="right"}}),B=()=>{if(n.maxScale<n.minScale)throw new Error("[Props Error]maxScale should greater than minSacle");let t=n.initScale;t>n.maxScale?t=n.maxScale:t<n.minScale&&(t=n.minScale),e.lastTransformData.scale=O(t/100),m(i.value)},k=()=>{B();const t=P();Object.entries(t).forEach(r=>{const[c,d]=r;_(document,c,d,{passive:!1,capture:!1})});const o=E(),s=Object.keys(t);Object.entries(o).forEach(r=>{const[c,d]=r,p=s.includes(c)?d:V(d,n.throttleSpan);_(u.value,c,p,{capture:n.useCapture,passive:!1})})},P=()=>D()?{wheel:t=>{t.ctrlKey&&z(t)}}:{touchmove:z},E=()=>D()?{mousedown:K,mousemove:U,mouseup:Z,mouseleave:F,wheel:J}:{touchstart:M,touchmove:Q,touchend:tt},z=t=>{t.preventDefault()},A=()=>{e.lastTransformData={scale:1,translateX:0,translateY:0},m(i.value),f("reset")},C=()=>{const{scale:t}=e.lastTransformData,o=(t*100+n.scaleStep)/100;e.lastTransformData.scale=Math.min(o,n.maxScale/100),m(i.value),f("zoom-in",e.lastTransformData)},N=()=>{const{scale:t}=e.lastTransformData,o=(t*100-n.scaleStep)/100;e.lastTransformData.scale=Math.max(o,n.minScale/100),m(i.value),f("zoom-out",e.lastTransformData)},_=(t,o,s,r)=>{t.addEventListener(o,s,r)},S=(t,o,s)=>{t.removeEventListener(o,s)},X=(t,o)=>{const{translateX:s,translateY:r}=e.lastTransformData,{deltaX:c,deltaY:d}=o,[p,at]=[s+c,r+d];e.lastTransformData={...e.lastTransformData,translateX:p,translateY:at},m(t),f("move",e.lastTransformData)},m=t=>{const{scale:o,translateX:s,translateY:r}=e.lastTransformData,c=O(o);t.style.transform=`matrix(${c}, 0, 0, ${c}, ${s}, ${r})`,e.lastTransformData.scale=c,f("update",e.lastTransformData)},Y=t=>{!n.emitClickOnDrag&&e.dragged&&(t.stopPropagation(),t.preventDefault())},K=t=>{e.readyToDrag=!0,e.lastPosition={x:t.clientX,y:t.clientY},n.emitClickOnDrag||(e.dragged=!1,_(u.value,"click",Y,{capture:!0}))},U=t=>{if(e.readyToDrag){t.stopPropagation(),t.preventDefault(),e.dragging=!0;const{clientX:o,clientY:s}=t,{x:r,y:c}=e.lastPosition,[d,p]=[o-r,s-c];X(i.value,{deltaX:d,deltaY:p}),e.lastPosition={x:o,y:s},n.emitClickOnDrag||(e.dragged=!0)}},Z=()=>{e.readyToDrag=!1,e.dragging=!1,S(u.value,"click",Y)},F=()=>{},J=t=>{const{ctrlKey:o,wheelDelta:s}=t;if(t.preventDefault(),t.stopPropagation(),o)s>0?C():N();else{const{deltaMode:r,wheelDeltaX:c,wheelDeltaY:d}=t;r===0&&(e.lastTransformData.translateX+=c,e.lastTransformData.translateY+=d),m(i.value)}},M=t=>{if(t.touches.length===1){const{clientX:o,clientY:s}=t.touches[0];e.lastPosition={x:o,y:s},e.readyToDrag=!0,e.dragging=!1,e.readyToScale=!1}else if(t.touches.length===2){e.readyToScale=!0,e.readyToDrag=!1,e.dragging=!1;const[o,s]=t.touches,r=o.clientX-s.clientX,c=o.clientY-s.clientY;e.lastPosition.distance=Math.sqrt(r*r+c*c);const d=[(o.clientX+r/2-e.lastTransformData.x)/e.lastTransformData.scale,(o.clientY+c/2-e.lastTransformData.y)/e.lastTransformData.scale];e.scaleTranslateProportion=[d[0]/i.offsetWidth,d[1]/i.offsetHeight]}},Q=t=>{if(t.preventDefault(),t.stopPropagation(),t.touches.length===1&&e.readyToDrag){e.dragging=!0;const{clientX:o,clientY:s}=t.touches[0],{x:r,y:c}=e.lastPosition,[d,p]=[o-r,s-c];X(i.value,{deltaX:d,deltaY:p}),e.lastPosition={...e.lastPosition,x:o,y:s}}else if(t.touches.length===2){if(!e.readyToScale){M(t);return}const[o,s]=t.touches,r=Math.sqrt((o.clientX-s.clientX)*(o.clientX-s.clientX)+(o.clientY-s.clientY)*(o.clientY-s.clientY));et(r/e.lastPosition.distance,!1),e.lastPosition.distance=r}},tt=t=>{e.readyToDrag=!1,e.dragging=!1,e.readyToScale=!1,e.isScaling=!1,e.lastPosition={x:0,y:0,distance:0}},et=(t,o=!0)=>{if(t===0&&t===1)return;const s=[i.offsetWidth*e.lastTransformData.scale,i.offsetHeight*e.lastTransformData.scale];let r=e.scaleTranslateProportion;if(o){const c=[(u.offsetWidth/2-e.lastTransformData.x)/e.lastTransformData.scale,(u.offsetHeight/2-e.lastTransformData.y)/e.lastTransformData.scale];r=[c[0]/u.offsetWidth,c[1]/u.offsetHeight]}e.lastTransformData.x+=s[0]*(1-t)*r[0]||0,e.lastTransformData.y+=s[1]*(1-t)*r[1]||0,e.lastTransformData.scale*=t,m(i.value)},O=t=>(t*100>n.maxScale?t=n.maxScale/100:t*100<n.minScale&&(t=n.minScale/100),t);return a.onMounted(()=>{k()}),a.onBeforeUnmount(()=>{Object.entries(E()).forEach(t=>{const[o,s]=t;S(u.value,o,s)}),Object.entries(P()).forEach(t=>{const[o,s]=t;S(document,o,s)})}),(t,o)=>(a.openBlock(),a.createElementBlock("div",{ref_key:"containerRef",ref:u,class:a.normalizeClass(["grabbing-box-container w-full h-full overflow-hidden flex flex-col relative",{"cursor-grab":!e.dragging,"cursor-grabbing":e.dragging}])},[n.scaleButtons?(a.openBlock(),a.createBlock(q,{key:0,scaling:a.unref(y),onZoomIn:C,onZoomOut:N,onReset:A,class:a.normalizeClass(["scale-button-group",{"custom-position-top":a.unref(h).top,"custom-position-bottom":a.unref(h).bottom,"custom-position-left":a.unref(h).left,"custom-position-right":a.unref(h).right}]),style:a.normalizeStyle(` --scale-buttons-space-x: ${n.scaleButtonsSpaceX}; --scale-buttons-space-y: ${n.scaleButtonsSpaceY}; `)},null,8,["scaling","class","style"])):a.createCommentVNode("",!0),a.createElementVNode("div",{ref_key:"contentBoxRef",ref:i,class:"grabbing-box w-full h-full",style:{"transform-origin":"center center","user-select":"none",transform:"matrix(1, 0, 0, 1, 0, 0)"}},[a.renderSlot(t.$slots,"default",{},void 0,!0)],512)],2))}}),[["__scopeId","data-v-58cc9f3c"]]);b.name="GrabbingBox",b.install=function(l){l.component(b.name,b)};const x=l=>{x.installed||(x.installed=!0,l.use(b))};typeof window<"u"&&window.Vue&&x(window.Vue),g.GrabbingBox=b,g.default=x,g.version=I,Object.defineProperties(g,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});