UNPKG

@ahmiao666/lucky-wheel-vue

Version:
3 lines (2 loc) 25.7 kB
!function(t,e){"object"==typeof exports&&typeof module<"u"?e(exports,require("vue")):"function"==typeof define&&define.amd?define(["exports","vue"],e):e((t=typeof globalThis<"u"?globalThis:t||self).LuckyWheelVue={},t.Vue)}(this,function(t,e){"use strict";class i{constructor(t,e){this.rotateDeg=0,this.speed=i.DEFAULTS.SPEED,this.accelerationTime=i.DEFAULTS.ACCELERATION_TIME,this.decelerationTime=i.DEFAULTS.DECELERATION_TIME,this.stopOffsetRange=i.DEFAULTS.STOP_OFFSET_RANGE,this.targetDirection=i.DEFAULTS.TARGET_DIRECTION,this.startTime=0,this.endTime=0,this.stopDeg=0,this.endDeg=0,this.prizeDeg=0,this.FPS=i.DEFAULTS.FPS,this.images={arrow:void 0,background:void 0,centerButtonBackground:void 0,centerButtonArrow:void 0,sectors:new Map,sectorContents:new Map},this.imageLoadStates={arrow:!1,background:!1,centerButtonBackground:!1,centerButtonArrow:!1,sectors:new Map,sectorContents:new Map},this.step=0,this.centerButtonAnimationTime=0,this.imageLoaders=[{name:"background",getSrc:()=>this.config.backgroundImage,onLoad:t=>{this.images.background=t},onError:t=>console.warn("背景图片加载失败:",t),setLoaded:t=>{this.imageLoadStates.background=t}},{name:"arrow",getSrc:()=>this.config.arrow?.image,onLoad:t=>{this.images.arrow=t},onError:t=>console.warn("箭头图片加载失败:",t),setLoaded:t=>{this.imageLoadStates.arrow=t}},{name:"centerButtonBackground",getSrc:()=>this.config.centerButton?.backgroundImage,onLoad:t=>{this.images.centerButtonBackground=t},onError:t=>console.warn("中心按钮背景图片加载失败:",t),setLoaded:t=>{this.imageLoadStates.centerButtonBackground=t}},{name:"centerButtonArrow",getSrc:()=>this.config.centerButton?.arrow?.image,onLoad:t=>{this.images.centerButtonArrow=t},onError:t=>console.warn("中心按钮箭头图片加载失败:",t),setLoaded:t=>{this.imageLoadStates.centerButtonArrow=t}}],this.loadArrowImage=()=>this.reloadImageByName("arrow"),this.loadCenterButtonBackgroundImage=()=>this.reloadImageByName("centerButtonBackground"),this.loadCenterButtonArrowImage=()=>this.reloadImageByName("centerButtonArrow"),this.setStopOffsetRange=t=>{this.stopOffsetRange=Math.max(0,Math.min(1,t))},this.setTargetDirection=t=>{this.targetDirection=(t%360+360)%360,this.draw()},this.setArrowConfig=this.createConfigSetter("arrow",void 0,()=>{void 0!==this.config.arrow?.image&&(this.imageLoadStates.arrow=!1,this.loadArrowImage())}),this.setArrowDistance=t=>this.setArrowConfig({distance:Math.max(0,t)}),this.setArrowVisible=t=>this.setArrowConfig({visible:t}),this.setBorderConfig=this.createConfigSetter("border"),this.setBorderWidth=t=>this.setBorderConfig({width:Math.max(0,t)}),this.setBorderColor=t=>this.setBorderConfig({color:t}),this.setBorderStyle=t=>this.setBorderConfig({style:t}),this.setInnerPadding=t=>{this.config.innerPadding=Math.max(0,t),this.draw()},this.setSectorStrokeConfig=this.createConfigSetter("sectorStroke"),this.setSectorStrokeWidth=t=>this.setSectorStrokeConfig({width:Math.max(0,t)}),this.setSectorStrokeColor=t=>this.setSectorStrokeConfig({color:t}),this.setCenterButtonConfig=this.createConfigSetter("centerButton",void 0,()=>{void 0!==this.config.centerButton?.backgroundImage&&(this.imageLoadStates.centerButtonBackground=!1,this.loadCenterButtonBackgroundImage()),void 0!==this.config.centerButton?.arrow?.image&&(this.imageLoadStates.centerButtonArrow=!1,this.loadCenterButtonArrowImage())}),this.setCenterButtonAnimation=t=>this.setCenterButtonConfig({animation:t}),this.setCenterButtonAnimationConfig=t=>this.setCenterButtonConfig({animation:t}),this.setCenterButtonAnimationSpeed=t=>{const e=this.getAnimationConfig();this.setCenterButtonAnimationConfig({enabled:e.enabled,speed:Math.max(0,t),scale:e.scale})},this.setCenterButtonAnimationScale=t=>{const e=this.getAnimationConfig();this.setCenterButtonAnimationConfig({enabled:e.enabled,speed:e.speed,scale:Math.max(0,Math.min(1,t))})},this.setSectorTextConfig=this.createSectorConfigSetter("textConfig"),this.setBatchSectorTextConfig=t=>{t.forEach(({sectorId:t,config:e})=>this.setSectorTextConfig(t,e))},this.getSectorTextConfigById=t=>this.findSector(t)?.textConfig,this.resetSectorTextConfig=t=>{const e=this.findSector(t);e&&(e.textConfig=void 0,this.draw())},this.setSectorTextFontSize=(t,e)=>this.setSectorTextConfig(t,{fontSize:Math.max(1,e)}),this.setSectorTextColor=(t,e)=>this.setSectorTextConfig(t,{color:e}),this.setSectorTextLineHeight=(t,e)=>this.setSectorTextConfig(t,{lineHeight:Math.max(1,e)}),this.setSectorTextMaxLines=(t,e)=>this.setSectorTextConfig(t,{maxLines:Math.max(1,e)}),this.setSectorTextDirection=(t,e)=>this.setSectorTextConfig(t,{direction:e}),this.setSectorTextOffset=(t,e,i)=>this.setSectorTextConfig(t,{offsetX:Math.max(-1,Math.min(1,e)),offsetY:Math.max(-1,Math.min(1,i))}),this.setSectorTextAlign=(t,e)=>this.setSectorTextConfig(t,{textAlign:e}),this.setSectorTextFont=(t,e,i)=>{const s={fontFamily:e};i&&(s.fontWeight=i),this.setSectorTextConfig(t,s)},this.setSectorTextRadius=(t,e)=>this.setSectorTextConfig(t,{textRadius:Math.max(.1,Math.min(1,e))}),this.setSectorContentImageConfig=(t,e)=>{const i=this.findSector(t);if(i){if(!i.contentImage&&e.url)i.contentImage={url:e.url,...e};else{if(!i.contentImage)return void console.warn(`扇形 ${t} 需要先设置图片URL`);Object.assign(i.contentImage,e)}e.url&&(this.imageLoadStates.sectorContents.set(t,!1),this.loadSectorContentImages()),this.draw()}},this.setSectorContentImage=(t,e,i)=>this.setSectorContentImageConfig(t,{url:e,...i}),this.removeSectorContentImage=t=>{const e=this.findSector(t);e&&(e.contentImage=void 0,this.images.sectorContents.delete(t),this.imageLoadStates.sectorContents.set(t,!0),this.draw())},this.setSectorContentImageSize=(t,e,i)=>this.setSectorContentImageConfig(t,{width:Math.max(1,e),height:Math.max(1,i)}),this.setSectorContentImageOffset=(t,e,i)=>this.setSectorContentImageConfig(t,{offsetX:Math.max(-1,Math.min(1,e)),offsetY:Math.max(-1,Math.min(1,i))}),this.setSectorContentImageRadius=(t,e)=>this.setSectorContentImageConfig(t,{imageRadius:Math.max(.1,Math.min(1,e))}),this.setSectorContentImageRotation=(t,e)=>this.setSectorContentImageConfig(t,{rotation:e}),this.setSectorContentImageOpacity=(t,e)=>this.setSectorContentImageConfig(t,{opacity:Math.max(0,Math.min(1,e))}),this.setSectorContentImageVisible=(t,e)=>this.setSectorContentImageConfig(t,{visible:e}),this.setBackgroundImage=t=>{this.config.backgroundImage=t,this.imageLoadStates.background=!1,this.reloadImageByName("background")},this.canvas=t,this.ctx=t.getContext("2d"),this.config=e,this.devicePixelRatio=window.devicePixelRatio||1,this.config.size||(this.config.size=this.getDefaultSize()),this.setupHighDPICanvas(this.config.size),this.stopOffsetRange=e.stopOffsetRange??i.DEFAULTS.STOP_OFFSET_RANGE,this.targetDirection=e.targetDirection??i.DEFAULTS.TARGET_DIRECTION,this.prizeDeg=360/e.sectors.length,this.setupCenterButtonMouseEvents(),this.loadAllImages(),this.draw(),this.startContinuousAnimation()}static{this.DEFAULTS={SPEED:20,ACCELERATION_TIME:2500,DECELERATION_TIME:2500,STOP_OFFSET_RANGE:.6,TARGET_DIRECTION:0,FPS:16.6,ANIMATION_SPEED:.001,MIN_SIZE:100,MAX_OFFSET_RATIO:.8,ARROW_DISTANCE_OFFSET:20,WHEEL_BORDER_OFFSET:20,CENTER_BUTTON:{DEFAULT_WIDTH:20,DEFAULT_HEIGHT:20,DEFAULT_COLOR:"#fff",DEFAULT_ARROW_SIZE:10,DEFAULT_ARROW_COLOR:"#333"},ARROW:{DEFAULT_SIZE:15,DEFAULT_COLOR:"#333",DEFAULT_IMAGE_WIDTH:30,DEFAULT_IMAGE_HEIGHT:30},SECTOR:{DEFAULT_STROKE_WIDTH:2,DEFAULT_STROKE_COLOR:"#fff",CONTENT_IMAGE:{DEFAULT_WIDTH:30,DEFAULT_HEIGHT:30,DEFAULT_RADIUS:.5,DEFAULT_OPACITY:1}}}}getDefaultSize(){const t=this.canvas.parentElement;if(!t)return 300;const e=t.getBoundingClientRect(),i=this.config.canvasPadding??0,s=e.width-2*i,o=e.height-2*i,n=Math.min(s,o);return Math.max(n,100)}setupHighDPICanvas(t){const e=t+2*(this.config.canvasPadding??0);this.canvas.style.width=e+"px",this.canvas.style.height=e+"px",this.canvas.width=Math.floor(e*this.devicePixelRatio),this.canvas.height=Math.floor(e*this.devicePixelRatio),this.ctx.scale(this.devicePixelRatio,this.devicePixelRatio),this.ctx.imageSmoothingEnabled=!0,this.ctx.imageSmoothingQuality="high"}setupCenterButtonMouseEvents(){this.canvas.addEventListener("mousemove",t=>{this.isPointInCenterButton(t)?this.canvas.style.cursor="pointer":this.canvas.style.cursor="default"}),this.canvas.addEventListener("mouseleave",()=>{this.canvas.style.cursor="default"}),this.canvas.addEventListener("click",t=>{this.isPointInCenterButton(t)&&(this.onCenterButtonClickCallback?this.onCenterButtonClickCallback():0===this.step&&this.start())})}isPointInCenterButton(t){const e=this.config.centerButton;if(!e||!1===e.visible)return!1;const i=this.canvas.getBoundingClientRect(),s=this.config.canvasPadding??0,o=this.config.size+2*s,n=t.clientX-i.left-o/2,a=t.clientY-i.top-o/2,r=n/((e.width??20)/2),c=a/((e.height??20)/2);return r*r+c*c<=1}loadAllImages(){this.imageLoaders.forEach(t=>this.loadSingleImage(t)),this.loadSectorImages(),this.loadSectorContentImages()}loadSingleImage(t){const e=t.getSrc();t.setLoaded(!e),this.loadImage(e,e=>{t.onLoad(e),t.setLoaded(!0),this.draw()},e=>{t.onError(e),t.setLoaded(!0),this.draw()})}loadImage(t,e,i){if(!t)return;if(t instanceof HTMLImageElement)return void e(t);const s=new Image;s.onload=()=>e(s),s.onerror=()=>{i?.("string"==typeof t?t:"Unknown image source")},s.src=t}loadMapImages(t,e,i,s,o,n){t().forEach(t=>{const a=e(t),r=i(t);a?(o.set(r,!1),this.loadImage(a,t=>{s.set(r,t),o.set(r,!0),this.draw()},t=>{console.warn(`${n}[${r}]:`,t),o.set(r,!0),this.draw()})):o.set(r,!0)})}loadSectorImages(){this.loadMapImages(()=>this.config.sectors,t=>t.image?.url,t=>t.id,this.images.sectors,this.imageLoadStates.sectors,"扇形图片加载失败")}loadSectorContentImages(){this.loadMapImages(()=>this.config.sectors,t=>t.contentImage?.url,t=>t.id,this.images.sectorContents,this.imageLoadStates.sectorContents,"扇形内容图片加载失败")}reloadImageByName(t){const e=this.imageLoaders.find(e=>e.name===t);e&&this.loadSingleImage(e)}getAnimationConfig(){const t=this.config.centerButton;if(!t)return{enabled:!1,speed:i.DEFAULTS.ANIMATION_SPEED,scale:.1};const e=t.animation;return!1===e?{enabled:!1,speed:i.DEFAULTS.ANIMATION_SPEED,scale:.1}:!0===e||void 0===e?{enabled:!0,speed:i.DEFAULTS.ANIMATION_SPEED,scale:.1}:{enabled:!1!==e.enabled,speed:e.speed??i.DEFAULTS.ANIMATION_SPEED,scale:e.scale??.1}}startContinuousAnimation(){const t=()=>{const e=this.getAnimationConfig();this.centerButtonAnimationTime+=16.6*e.speed,!1!==this.config.centerButton?.visible&&e.enabled&&this.draw(),this.continuousAnimationId=requestAnimationFrame(t)};t()}stopContinuousAnimation(){this.continuousAnimationId&&(cancelAnimationFrame(this.continuousAnimationId),this.continuousAnimationId=void 0)}start(){0===this.step&&(this.startTime=Date.now(),this.prizeFlag=void 0,this.step=1,this.run())}stop(t,e){if(0===this.step||3===this.step)return;this.onStopCallback=e,t=t||this.getRandomSectorId();const i=this.config.sectors.findIndex(e=>e.id===t);if(-1===i)return this.step=0,void(this.prizeFlag=-1);this.step=2,this.prizeFlag=i}setCenterButtonClickCallback(t){this.onCenterButtonClickCallback=t}updateConfig(t,e,i){const s=t.split(".");let o=this.config;for(let t=0;t<s.length-1;t++)o[s[t]]||(o[s[t]]={}),o=o[s[t]];const n=s[s.length-1];o[n]={...o[n],...e},i?.(),this.draw()}createConfigSetter(t,e,i){return s=>{e&&"object"==typeof s&&Object.keys(s).forEach(t=>{const i=s[t];void 0!==i&&(s[t]=e(i))}),this.updateConfig(t,s,i)}}findSector(t){const e=this.config.sectors.find(e=>e.id===t);return e||console.warn(`找不到ID为 ${t} 的扇形`),e}createSectorConfigSetter(t,e){return(i,s)=>{const o=this.findSector(i);if(!o)return;const n=o[t]||{},a=e&&"object"==typeof s?Object.fromEntries(Object.entries(s).map(([t,i])=>[t,e(i)])):s;o[t]={...n,...a},this.draw()}}run(t=0){if(0===this.step){if(void 0!==this.prizeFlag&&this.prizeFlag>=0){const t=this.config.sectors[this.prizeFlag];this.onStopCallback?.(t)}return}if(-1===this.prizeFlag)return;3===this.step&&!this.endDeg&&this.carveOnGunwaleOfAMovingBoat();const e=Date.now()-this.startTime,i=Date.now()-this.endTime;let s=this.rotateDeg;if(1===this.step||e<this.accelerationTime){this.FPS=e/t;const i=this.quadEaseIn(e,0,this.speed,this.accelerationTime);i===this.speed&&(this.step=2),s+=i%360}else 2===this.step?(s+=this.speed%360,void 0!==this.prizeFlag&&this.prizeFlag>=0&&(this.step=3,this.stopDeg=0,this.endDeg=0)):3===this.step&&(s=this.quadEaseOut(i,this.stopDeg,this.endDeg,this.decelerationTime),i>=this.decelerationTime&&(this.step=0));this.rotateDeg=s,this.draw(),this.animationId=requestAnimationFrame(()=>this.run(t+1))}carveOnGunwaleOfAMovingBoat(){const{prizeFlag:t,prizeDeg:e,rotateDeg:i}=this;this.endTime=Date.now();const s=this.stopDeg=i,o=this.speed,n=(2*Math.random()-1)*this.stopOffsetRange*e*.8/2;let a=0,r=0,c=0;for(;++a;){const h=360*a-t*e-i+n-e/2;let g=this.quadEaseOut(this.FPS,s,h,this.decelerationTime)-s;if(g>o){this.endDeg=o-r>g-o?h:c;break}c=h,r=g}}quadEaseIn(t,e,i,s){return i*(t/=s)*t+e}quadEaseOut(t,e,i,s){return-i*(t/=s)*(t-2)+e}draw(){const t=this.config.size,e=t+2*(this.config.canvasPadding??0),i=e/2,s=e/2,o=t/2-(this.config.border?.width??0)/2,n=o-(this.config.innerPadding??0);this.ctx.clearRect(0,0,e,e),this.ctx.save(),this.ctx.translate(i,s),this.drawBackgroundImage(o);const a=this.rotateDeg-90+this.prizeDeg/2+this.targetDirection;this.ctx.rotate(a*Math.PI/180);const r=2*Math.PI/this.config.sectors.length;this.config.sectors.forEach((t,e)=>{const i=e*r-r/2,s=i+r;this.drawSector(t,i,s,n)}),this.drawSectorDividers(r,n),this.ctx.restore(),this.drawWheelBorder(i,s,o),this.drawArrow(i,s),this.drawCenterButton(i,s)}drawBackgroundImage(t){if(!this.images.background||!this.imageLoadStates.background)return;this.ctx.save(),this.ctx.beginPath(),this.ctx.arc(0,0,t,0,2*Math.PI),this.ctx.clip();const e=2*t;this.ctx.drawImage(this.images.background,-t,-t,e,e),this.ctx.restore()}drawSector(t,e,i,s){this.ctx.beginPath(),this.ctx.arc(0,0,s,e,i),this.ctx.lineTo(0,0),this.ctx.fillStyle=t.color,this.ctx.fill(),this.drawSectorImage(t,e,i,s),this.drawSectorContentImage(t,e,i,s),this.drawSectorText(t,e,i,s)}getDefaultTextConfig(){return{fontSize:14,color:"#fff",lineHeight:16,maxLines:2,direction:"horizontal",offsetX:0,offsetY:0,textAlign:"center",fontFamily:"Arial",fontWeight:"normal",textRadius:.65}}getSectorTextConfig(t){return{...this.getDefaultTextConfig(),...t.textConfig}}drawSectorText(t,e,i,s){if(!t.text)return;const o=this.getSectorTextConfig(t),n=i-e,a=e+n/2;this.ctx.save(),this.ctx.fillStyle=o.color,this.ctx.font=`${o.fontWeight} ${o.fontSize}px ${o.fontFamily}`,this.ctx.textBaseline="middle";const r=s*o.textRadius,c=Math.cos(a)*r,h=Math.sin(a)*r;this.ctx.translate(c,h),"horizontal"===o.direction?this.ctx.rotate(a+Math.PI/2):this.ctx.rotate(a);const g=2*r*Math.sin(n/2),l=Math.max(o.fontSize/4,2),d=g/2-l,f=s-r-l,u=r-l,m=.8*Math.min(f,u);let x,S;"horizontal"===o.direction?(x=o.offsetX*d,S=o.offsetY*m):(x=o.offsetY*d,S=o.offsetX*m),this.ctx.translate(x,S);const{maxTextWidth:C,maxTextHeight:T}=this.calculateTextArea(n,r,o.direction);this.createTextClipPath(C,T,o.textAlign);const I=this.wrapTextWithConfig(t.text,C,o);this.renderTextLines(I,o,C,T),this.ctx.restore()}calculateTextArea(t,e,i){if("horizontal"===i){return{maxTextWidth:2*e*Math.sin(t/2)*.95,maxTextHeight:.7*e}}return{maxTextWidth:.8*e,maxTextHeight:2*e*Math.sin(t/2)*.9}}createTextClipPath(t,e,i){this.ctx.beginPath(),this.ctx.rect(-t/2,-e/2,t,e),this.ctx.clip()}wrapTextWithConfig(t,e,i){const s=[];let o="";const n=Array.from(t);for(let t=0;t<n.length;t++){const a=n[t],r=o+a;if(this.ctx.measureText(r).width>e&&""!==o){if(s.push(o.trim()),o=a,s.length>=i.maxLines-1){const i=o+n.slice(t+1).join("");if(this.ctx.measureText(i).width>e){let i=o;for(let s=t+1;s<n.length;s++){const t=n[s],o=i+t;if(this.ctx.measureText(o+"...").width>e)break;i+=t}for(;this.ctx.measureText(i+"...").width>e&&i.length>0;)i=i.slice(0,-1);o=i+"..."}else o=i;s.push(o.trim());break}}else o=r}return o.trim()&&s.length<i.maxLines&&s.push(o.trim()),s}renderTextLines(t,e,i,s){const o=-t.length*e.lineHeight/2+e.lineHeight/2;t.forEach((t,s)=>{const n=o+s*e.lineHeight;let a=0;"left"===e.textAlign?(this.ctx.textAlign="left",a=-i/2):"right"===e.textAlign?(this.ctx.textAlign="right",a=i/2):(this.ctx.textAlign="center",a=0),this.ctx.fillText(t,a,n)})}drawSectorDividers(t,e){const i=this.config.sectorStroke;if(i&&(i.width??0)>0){const s=this.config.sectors.length;this.ctx.strokeStyle=i.color??"#fff",this.ctx.lineWidth=i.width??2,this.ctx.setLineDash([]),this.ctx.lineCap="round",this.ctx.lineJoin="round";for(let i=0;i<s;i++){const s=(i+1)*t-t/2;this.ctx.beginPath(),this.ctx.moveTo(0,0),this.ctx.lineTo(Math.cos(s)*e,Math.sin(s)*e),this.ctx.stroke()}}}drawSectorImage(t,e,i,s){const o=this.images.sectors.get(t.id),n=this.imageLoadStates.sectors.get(t.id);if(!o||!n||!t.image)return;let a,r;if(this.ctx.save(),this.ctx.beginPath(),this.ctx.arc(0,0,s,e,i),this.ctx.lineTo(0,0),this.ctx.closePath(),this.ctx.clip(),void 0!==t.image.width&&void 0!==t.image.height)a=t.image.width,r=t.image.height;else{const t=i-e;a=2*s*Math.sin(t/2),r=s}const c=.5*s,h=e+(i-e)/2,g=Math.cos(h)*c,l=Math.sin(h)*c;this.ctx.translate(g,l),this.ctx.rotate(h+Math.PI/2),this.ctx.drawImage(o,-a/2,-r/2,a,r),this.ctx.restore()}drawSectorContentImage(t,e,i,s){if(!t.contentImage)return;const o=this.images.sectorContents.get(t.id),n=this.imageLoadStates.sectorContents.get(t.id);if(!o||!n||!1===t.contentImage.visible)return;this.ctx.save();const a=this.getDefaultContentImageConfig(t.contentImage),r=e+(i-e)/2,c=s*a.imageRadius,h=Math.cos(r)*c,g=Math.sin(r)*c,l=.3*s,d=-Math.sin(r),f=Math.cos(r),u=Math.cos(r),m=Math.sin(r),x=a.offsetX*l,S=a.offsetY*l,C=h+d*x+u*S,T=g+f*x+m*S;this.ctx.translate(C,T),this.ctx.rotate(r+a.rotation*Math.PI/180),this.ctx.globalAlpha=a.opacity,this.ctx.drawImage(o,-a.width/2,-a.height/2,a.width,a.height),this.ctx.restore()}getDefaultContentImageConfig(t){return{url:t.url,width:t.width??30,height:t.height??30,offsetX:t.offsetX??0,offsetY:t.offsetY??0,imageRadius:t.imageRadius??.5,rotation:t.rotation??0,opacity:t.opacity??1,visible:t.visible??!0}}drawArrow(t,e){const i=this.config.arrow||{};if(!1===i.visible||!this.imageLoadStates.arrow)return;const s=this.config.size/2-20,o=i.distance??s;if(this.ctx.save(),this.ctx.translate(t,e),this.ctx.rotate(this.targetDirection*Math.PI/180),this.images.arrow&&i.image){const t=i.imageWidth??30,e=i.imageHeight??30,s=(i.size??15)/15,n=t*s,a=e*s;this.ctx.drawImage(this.images.arrow,-n/2,-o-a/2,n,a)}else{const t=i.size??15,e=i.color??"#333";this.ctx.beginPath(),this.ctx.moveTo(0,-o),this.ctx.lineTo(-t,-o-1.2*t),this.ctx.lineTo(t,-o-1.2*t),this.ctx.closePath(),this.ctx.fillStyle=e,this.ctx.fill(),this.ctx.strokeStyle="#fff",this.ctx.lineWidth=1,this.ctx.stroke()}this.ctx.restore()}drawCenterButton(t,e){const i=this.config.centerButton;if(!i||!1===i.visible||!this.imageLoadStates.centerButtonBackground||!this.imageLoadStates.centerButtonArrow)return;let s=i.width??20,o=i.height??20;const n=i.backgroundColor??"#fff";let a=1;const r=this.getAnimationConfig();if(r.enabled&&(a=1+Math.sin(this.centerButtonAnimationTime)*r.scale,s*=a,o*=a),this.ctx.save(),this.ctx.translate(t,e),this.ctx.beginPath(),s===o?this.ctx.arc(0,0,s/2,0,2*Math.PI):this.ctx.ellipse(0,0,s/2,o/2,0,0,2*Math.PI),this.ctx.fillStyle=n,this.ctx.fill(),i.border){const t=i.border.width??2,e=i.border.color??"#333",s=i.border.style??"solid";this.ctx.strokeStyle=e,this.ctx.lineWidth=t,this.ctx.lineCap="round",this.ctx.lineJoin="round","dashed"===s?this.ctx.setLineDash([3*t,2*t]):"dotted"===s?this.ctx.setLineDash([t,t]):this.ctx.setLineDash([]),this.ctx.stroke()}this.images.centerButtonBackground&&i.backgroundImage&&(this.ctx.save(),this.ctx.clip(),this.ctx.drawImage(this.images.centerButtonBackground,-s/2,-o/2,s,o),this.ctx.restore()),i.arrow&&this.drawCenterButtonArrow(i.arrow),this.ctx.restore()}drawCenterButtonArrow(t){if(!t)return;let e=t.size??10;const i=t.color??"#333",s=t.offsetY??0,o=this.getAnimationConfig();if(o.enabled){e*=1+Math.sin(this.centerButtonAnimationTime)*o.scale}if(this.ctx.save(),this.ctx.rotate(this.targetDirection*Math.PI/180),this.ctx.translate(0,s),this.images.centerButtonArrow&&t.image){const i=e/10,s=(t.imageWidth??20)*i,o=(t.imageHeight??20)*i;this.ctx.drawImage(this.images.centerButtonArrow,-s/2,-o/2,s,o)}else{this.ctx.beginPath();const t=e/2;this.ctx.moveTo(0,-t),this.ctx.lineTo(.6*-t,t),this.ctx.lineTo(.6*t,t),this.ctx.closePath(),this.ctx.fillStyle=i,this.ctx.fill(),this.ctx.strokeStyle="#fff",this.ctx.lineWidth=1,this.ctx.stroke()}this.ctx.restore()}drawWheelBorder(t,e,i){const s=this.config.border;if(!s)return;const o=s.width??2,n=s.color??"#333",a=s.style??"solid";this.ctx.save(),this.ctx.translate(t,e),this.ctx.beginPath(),this.ctx.arc(0,0,i,0,2*Math.PI),this.ctx.strokeStyle=n,this.ctx.lineWidth=o,this.ctx.lineCap="round",this.ctx.lineJoin="round","dashed"===a?this.ctx.setLineDash([3*o,2*o]):"dotted"===a?this.ctx.setLineDash([o,o]):this.ctx.setLineDash([]),this.ctx.stroke(),this.ctx.restore()}getRandomSectorId(){return this.config.sectors[Math.floor(Math.random()*this.config.sectors.length)].id}setSectorImage(t,e,i){const s=this.config.sectors.find(e=>e.id===t);s?(s.image=e?{url:e,width:i?.width,height:i?.height}:void 0,e?(this.imageLoadStates.sectors.set(t,!1),this.loadSectorImages()):(this.imageLoadStates.sectors.set(t,!0),this.images.sectors.delete(t),this.draw())):console.warn(`找不到ID为 ${t} 的扇形`)}destroy(){this.animationId&&cancelAnimationFrame(this.animationId),this.stopContinuousAnimation(),this.canvas.style.cursor="default"}}var s=((t,e)=>{const i=t.__vccOpts||t;for(const[t,s]of e)i[t]=s;return i})(e.defineComponent({__name:"VueLuckyWheelWrapper",props:{config:{type:Object,required:!0},className:{type:String,required:!1,default:""},style:{type:Object,required:!1,default:()=>({})}},emits:["stop","centerButtonClick","start","ready"],setup(t,{expose:s,emit:o}){const n=t,a=o,r=e.ref(),c=e.ref(null),h=async()=>{if(r.value)try{c.value&&c.value.destroy();const t=new i(r.value,n.config);c.value=t,t.setCenterButtonClickCallback(()=>{a("start"),a("centerButtonClick")}),a("ready",t)}catch(t){console.error("初始化幸运转盘失败:",t)}},g=()=>{c.value&&(c.value.destroy(),c.value=null)};return e.watch(()=>n.config,()=>{e.nextTick(()=>{h()})},{deep:!0}),e.onMounted(()=>{e.nextTick(()=>{h()})}),e.onUnmounted(()=>{g()}),s({getEngine:()=>c.value,start:()=>{c.value&&(a("start"),c.value.start())},stop:(t,e)=>{c.value&&c.value.stop(t,t=>{e?.(t),a("stop",t)})},setStopOffsetRange:t=>{c.value?.setStopOffsetRange(t)},setTargetDirection:t=>{c.value?.setTargetDirection(t)},setArrowConfig:t=>{c.value?.setArrowConfig(t)},setArrowDistance:t=>{c.value?.setArrowDistance(t)},setArrowVisible:t=>{c.value?.setArrowVisible(t)},setBorderConfig:t=>{c.value?.setBorderConfig(t)},setBorderWidth:t=>{c.value?.setBorderWidth(t)},setBorderColor:t=>{c.value?.setBorderColor(t)},setBorderStyle:t=>{c.value?.setBorderStyle(t)},setInnerPadding:t=>{c.value?.setInnerPadding(t)},setCenterButtonClickCallback:t=>{c.value?.setCenterButtonClickCallback(t)},setSectorStrokeConfig:t=>{c.value?.setSectorStrokeConfig(t)},setSectorStrokeWidth:t=>{c.value?.setSectorStrokeWidth(t)},setSectorStrokeColor:t=>{c.value?.setSectorStrokeColor(t)},setCenterButtonConfig:t=>{c.value?.setCenterButtonConfig(t)},setCenterButtonAnimation:t=>{c.value?.setCenterButtonAnimation(t)},setCenterButtonAnimationConfig:t=>{c.value?.setCenterButtonAnimationConfig(t)},setCenterButtonAnimationSpeed:t=>{c.value?.setCenterButtonAnimationSpeed(t)},setCenterButtonAnimationScale:t=>{c.value?.setCenterButtonAnimationScale(t)},setBackgroundImage:t=>{c.value?.setBackgroundImage(t)},setSectorImage:(t,e,i)=>{c.value?.setSectorImage(t,e,i)},setSectorTextConfig:(t,e)=>{c.value?.setSectorTextConfig(t,e)},setBatchSectorTextConfig:t=>{c.value?.setBatchSectorTextConfig(t)},getSectorTextConfigById:t=>c.value?.getSectorTextConfigById(t),resetSectorTextConfig:t=>{c.value?.resetSectorTextConfig(t)},setSectorTextFontSize:(t,e)=>{c.value?.setSectorTextFontSize(t,e)},setSectorTextColor:(t,e)=>{c.value?.setSectorTextColor(t,e)},setSectorTextLineHeight:(t,e)=>{c.value?.setSectorTextLineHeight(t,e)},setSectorTextMaxLines:(t,e)=>{c.value?.setSectorTextMaxLines(t,e)},setSectorTextDirection:(t,e)=>{c.value?.setSectorTextDirection(t,e)},setSectorTextOffset:(t,e,i)=>{c.value?.setSectorTextOffset(t,e,i)},setSectorTextAlign:(t,e)=>{c.value?.setSectorTextAlign(t,e)},setSectorTextFont:(t,e,i)=>{c.value?.setSectorTextFont(t,e,i)},setSectorTextRadius:(t,e)=>{c.value?.setSectorTextRadius(t,e)},setSectorContentImageConfig:(t,e)=>{c.value?.setSectorContentImageConfig(t,e)},setSectorContentImage:(t,e,i)=>{c.value?.setSectorContentImage(t,e,i)},removeSectorContentImage:t=>{c.value?.removeSectorContentImage(t)},setSectorContentImageSize:(t,e,i)=>{c.value?.setSectorContentImageSize(t,e,i)},setSectorContentImageOffset:(t,e,i)=>{c.value?.setSectorContentImageOffset(t,e,i)},setSectorContentImageRadius:(t,e)=>{c.value?.setSectorContentImageRadius(t,e)},setSectorContentImageRotation:(t,e)=>{c.value?.setSectorContentImageRotation(t,e)},setSectorContentImageOpacity:(t,e)=>{c.value?.setSectorContentImageOpacity(t,e)},setSectorContentImageVisible:(t,e)=>{c.value?.setSectorContentImageVisible(t,e)},destroy:g}),(t,i)=>(e.openBlock(),e.createElementBlock("canvas",{ref_key:"canvasRef",ref:r,class:e.normalizeClass(t.className),style:e.normalizeStyle(t.style)},null,6))}}),[["__scopeId","data-v-880743bf"]]);t.LuckyWheelEngine=i,t.VueLuckyWheel=s,t.default=s,Object.defineProperty(t,"__esModule",{value:!0})}); //# sourceMappingURL=index.umd.js.map