index.esm.js.map 160 KB

1
  1. {"version":3,"file":"index.esm.js","sources":["../src/utils/polyfill.js","../src/utils/index.ts","../src/observer/dep.ts","../src/observer/utils.ts","../src/observer/array.ts","../src/observer/index.ts","../src/observer/watcher.ts","../src/lib/lucky.ts","../src/utils/math.ts","../src/utils/tween.ts","../src/lib/wheel.ts","../src/lib/grid.ts","../src/lib/slot.ts","../src/utils/image.ts"],"sourcesContent":["/**\n * 由于部分低版本下的某些 app 可能会缺少某些原型方法, 这里增加兼容\n */\n\n// ie11 不兼容 includes 方法\nif (!Array.prototype.includes) {\n Object.defineProperty(Array.prototype, 'includes', {\n value: function(valueToFind, fromIndex) {\n\n if (this == null) {\n throw new TypeError('\"this\" is null or not defined');\n }\n\n // 1. Let O be ? ToObject(this value).\n var o = Object(this);\n\n // 2. Let len be ? ToLength(? Get(O, \"length\")).\n var len = o.length >>> 0;\n\n // 3. If len is 0, return false.\n if (len === 0) {\n return false;\n }\n\n // 4. Let n be ? ToInteger(fromIndex).\n // (If fromIndex is undefined, this step produces the value 0.)\n var n = fromIndex | 0;\n\n // 5. If n ≥ 0, then\n // a. Let k be n.\n // 6. Else n < 0,\n // a. Let k be len + n.\n // b. If k < 0, let k be 0.\n var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);\n\n function sameValueZero(x, y) {\n return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));\n }\n\n // 7. Repeat, while k < len\n while (k < len) {\n // a. Let elementK be the result of ? Get(O, ! ToString(k)).\n // b. If SameValueZero(valueToFind, elementK) is true, return true.\n if (sameValueZero(o[k], valueToFind)) {\n return true;\n }\n // c. Increase k by 1.\n k++;\n }\n\n // 8. Return false\n return false;\n }\n });\n}\n\n// vivo x7 下网易云游戏 app 缺少 includes 方法\nif (!String.prototype.includes) {\n String.prototype.includes = function(search, start) {\n 'use strict';\n if (typeof start !== 'number') {\n start = 0;\n }\n if (start + search.length > this.length) {\n return false;\n } else {\n return this.indexOf(search, start) !== -1;\n }\n };\n}\n\n// vivo x7 下网易云游戏 app 缺少 find 方法\nif (!Array.prototype.find) {\n Object.defineProperty(Array.prototype, 'find', {\n value: function(predicate) {\n // 1. Let O be ? ToObject(this value).\n if (this == null) {\n throw new TypeError('\"this\" is null or not defined');\n }\n var o = Object(this);\n // 2. Let len be ? ToLength(? Get(O, \"length\")).\n var len = o.length >>> 0;\n // 3. If IsCallable(predicate) is false, throw a TypeError exception.\n if (typeof predicate !== 'function') {\n throw new TypeError('predicate must be a function');\n }\n // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.\n var thisArg = arguments[1];\n // 5. Let k be 0.\n var k = 0;\n // 6. Repeat, while k < len\n while (k < len) {\n // a. Let Pk be ! ToString(k).\n // b. Let kValue be ? Get(O, Pk).\n // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).\n // d. If testResult is true, return kValue.\n var kValue = o[k];\n if (predicate.call(thisArg, kValue, k, o)) {\n return kValue;\n }\n // e. Increase k by 1.\n k++;\n }\n // 7. Return undefined.\n return void 0;\n }\n });\n}\n","/**\n * 判断是否是期望的类型\n * @param { unknown } param 将要判断的变量\n * @param { ...string } types 期望的类型\n * @return { boolean } 返回期望是否正确\n */\nexport const isExpectType = (param: unknown, ...types: string[]): boolean => {\n return types.some(type => Object.prototype.toString.call(param).slice(8, -1).toLowerCase() === type)\n}\n\nexport const get = (data: object, strKeys: string) => {\n const keys = strKeys.split('.')\n for (let key of keys) {\n const res = data[key]\n if (!isExpectType(res, 'object', 'array')) return res\n data = res\n }\n return data\n}\n\nexport const has = (data: object, key: string | number): boolean => {\n return Object.prototype.hasOwnProperty.call(data, key)\n}\n\n/**\n * 移除\\n\n * @param { string } str 将要处理的字符串\n * @return { string } 返回新的字符串\n */\nexport const removeEnter = (str: string): string => {\n return [].filter.call(str, s => s !== '\\n').join('')\n}\n\n/**\n * 把任何数据类型转成数字\n * @param num \n */\nexport const getNumber = (num: unknown): number => {\n if (num === null) return 0\n if (typeof num === 'object') return NaN\n if (typeof num === 'number') return num\n if (typeof num === 'string') {\n if (num[num.length - 1] === '%') {\n return Number(num.slice(0, -1)) / 100\n }\n return Number(num)\n }\n return NaN\n}\n\n/**\n * 判断颜色是否有效 (透明色 === 无效)\n * @param color 颜色\n */\nexport const hasBackground = (color: string | undefined | null): boolean => {\n if (typeof color !== 'string') return false\n color = color.toLocaleLowerCase().trim()\n if (color === 'transparent') return false\n if (/^rgba/.test(color)) {\n const alpha = /([^\\s,]+)\\)$/.exec(color)\n if (getNumber(alpha) === 0) return false\n }\n return true\n}\n\n/**\n * 通过padding计算\n * @return { object } block 边框信息\n */\nexport const computePadding = (\n block: { padding?: string },\n getLength: Function\n): [number, number, number, number] => {\n let padding = block.padding?.split(' ').map(n => getLength(n)) || [0],\n paddingTop = 0,\n paddingBottom = 0,\n paddingLeft = 0,\n paddingRight = 0\n switch (padding.length) {\n case 1:\n paddingTop = paddingBottom = paddingLeft = paddingRight = padding[0]\n break\n case 2:\n paddingTop = paddingBottom = padding[0]\n paddingLeft = paddingRight = padding[1]\n break\n case 3:\n paddingTop = padding[0]\n paddingLeft = paddingRight = padding[1]\n paddingBottom = padding[2]\n break\n default:\n paddingTop = padding[0]\n paddingBottom = padding[1]\n paddingLeft = padding[2]\n paddingRight = padding[3]\n }\n // 检查是否单独传入值, 并且不是0\n const res = { paddingTop, paddingBottom, paddingLeft, paddingRight }\n for (let key in res) {\n // 是否含有这个属性, 并且是数字或字符串\n res[key] = has(block, key) && isExpectType(block[key], 'string', 'number')\n ? getLength(block[key])\n : res[key]\n }\n return [paddingTop, paddingBottom, paddingLeft, paddingRight]\n}\n\n/**\n * 节流函数\n * @param fn 将要处理的函数\n * @param wait 时间, 单位为毫秒\n * @returns 包装好的节流函数\n */\nexport const throttle = (fn: Function, wait = 300) => {\n let timeId = null as any\n return function (this: any, ...args: any[]) {\n if (timeId) return\n timeId = setTimeout(() => {\n fn.apply(this, args)\n clearTimeout(timeId)\n timeId = null\n }, wait)\n }\n}\n\n/**\n * 通过概率计算出一个奖品索引\n * @param { Array<number | undefined> } rangeArr 概率\n * @returns { number } 中奖索引\n */\nexport const computeRange = (rangeArr: Array<number | undefined>): number => {\n const ascendingArr: number[] = []\n // 额外增加 map 来优化 ts 的类型推断\n const sum = rangeArr.map(num => Number(num)).reduce((prev, curr) => {\n if (curr > 0) { // 大于0\n const res = prev + curr\n ascendingArr.push(res)\n return res\n } else { // 小于等于0或NaN\n ascendingArr.push(NaN)\n return prev\n }\n }, 0)\n const random = Math.random() * sum\n return ascendingArr.findIndex(num => random <= num)\n}\n\n/**\n * 根据宽度分割字符串, 来达到换行的效果\n * @param text \n * @param maxWidth \n * @returns \n */\nexport const splitText = (\n ctx: CanvasRenderingContext2D,\n text: string,\n getWidth: (lines: string[]) => number,\n lineClamp: number = Infinity\n): string[] => {\n // 如果 lineClamp 设置不正确, 则忽略该属性\n if (lineClamp <= 0) lineClamp = Infinity\n let str = ''\n const lines = []\n const EndWidth = ctx.measureText('...').width\n for (let i = 0; i < text.length; i++) {\n str += text[i]\n let currWidth = ctx.measureText(str).width\n const maxWidth = getWidth(lines)\n // 如果正在计算最后一行, 则加上三个小点的宽度\n if (lineClamp === lines.length + 1) currWidth += EndWidth\n // 如果已经没有宽度了, 就没有必要再计算了\n if (maxWidth < 0) return lines\n // 如果当前一行的宽度不够了, 则处理下一行\n if (currWidth > maxWidth) {\n lines.push(str.slice(0, -1))\n str = text[i]\n }\n // 如果现在是最后一行, 则加上三个小点并跳出\n if (lineClamp === lines.length) {\n lines[lines.length - 1] += '...'\n return lines\n }\n }\n if (str) lines.push(str)\n if (!lines.length) lines.push(text)\n return lines\n}\n\n// 获取一个重新排序的数组\nexport const getSortedArrayByIndex = <T>(arr: T[], order: number[]): T[] => {\n const map: { [key: number]: T } = {}, res = []\n for (let i = 0; i < arr.length; i++) {\n map[i] = arr[i]\n }\n for (let i = 0; i < order.length; i++) {\n const curr = map[order[i]]\n if (curr) (res[i] = curr)\n }\n return res\n}\n","import Watcher from './watcher'\n\nexport default class Dep {\n static target: Watcher | null\n private subs: Array<Watcher>\n\n /**\n * 订阅中心构造器\n */\n constructor () {\n this.subs = []\n }\n\n /**\n * 收集依赖\n * @param {*} sub \n */\n public addSub (sub: Watcher) {\n // 此处临时使用includes防重复添加\n if (!this.subs.includes(sub)) {\n this.subs.push(sub)\n }\n }\n\n /**\n * 派发更新\n */\n public notify () {\n this.subs.forEach(sub => {\n sub.update()\n })\n }\n}\n","\nimport { isExpectType } from '../utils'\n\nexport const hasProto = '__proto__' in {}\n\nexport function def (obj: object, key: string | number, val: any, enumerable?: boolean) {\n Object.defineProperty(obj, key, {\n value: val,\n enumerable: !!enumerable,\n writable: true,\n configurable: true\n })\n}\n\nexport function parsePath (path: string) {\n path += '.'\n let segments: string[] = [], segment = ''\n for (let i = 0; i < path.length; i++) {\n let curr = path[i]\n if (/\\[|\\./.test(curr)) {\n segments.push(segment)\n segment = ''\n } else if (/\\W/.test(curr)) {\n continue\n } else {\n segment += curr\n }\n }\n return function (data: object | any[]) {\n return segments.reduce((data, key) => {\n return data[key]\n }, data)\n }\n}\n\nexport function traverse (value: any) {\n // const seenObjects = new Set()\n const dfs = (data: any) => {\n if (!isExpectType(data, 'array', 'object')) return\n Object.keys(data).forEach(key => {\n const value = data[key]\n dfs(value)\n })\n }\n dfs(value)\n // seenObjects.clear()\n}","/**\n * 重写数组的原型方法\n */\nconst oldArrayProto = Array.prototype\nconst newArrayProto = Object.create(oldArrayProto)\nconst methods = ['push', 'pop', 'shift', 'unshift', 'sort', 'splice', 'reverse']\nmethods.forEach(method => {\n newArrayProto[method] = function (...args: any[]) {\n const res = oldArrayProto[method].apply(this, args)\n const luckyOb = this['__luckyOb__']\n if (['push', 'unshift', 'splice'].includes(method)) luckyOb.walk(this)\n luckyOb.dep.notify()\n return res\n }\n})\n\nexport { newArrayProto }\n","import Dep from './dep'\nimport { hasProto, def } from './utils'\nimport { newArrayProto } from './array'\n\nexport default class Observer {\n value: any\n dep: Dep\n\n /**\n * 观察者构造器\n * @param value \n */\n constructor (value: any) {\n // this.value = value\n this.dep = new Dep()\n // 将响应式对象代理到当前value上面, 并且将当前的enumerable设置为false\n def(value, '__luckyOb__', this)\n if (Array.isArray(value)) { // 如果是数组, 则重写原型方法\n if (hasProto) {\n value['__proto__'] = newArrayProto\n } else {\n Object.getOwnPropertyNames(newArrayProto).forEach(key => {\n def(value, key, newArrayProto[key])\n })\n }\n }\n this.walk(value)\n }\n\n walk (data: object | any[]) {\n Object.keys(data).forEach(key => {\n defineReactive(data, key, data[key])\n })\n }\n}\n\n/**\n * 处理响应式\n * @param { Object | Array } data\n */\nexport function observe (data: any): Observer | void {\n if (!data || typeof data !== 'object') return\n let luckyOb: Observer | void\n if ('__luckyOb__' in data) {\n luckyOb = data['__luckyOb__']\n } else {\n luckyOb = new Observer(data)\n }\n return luckyOb\n}\n\n/**\n * 重写 setter / getter\n * @param {*} data \n * @param {*} key \n * @param {*} val \n */\nexport function defineReactive (data: any, key: string | number, val: any) {\n const dep = new Dep()\n const property = Object.getOwnPropertyDescriptor(data, key)\n if (property && property.configurable === false) {\n return\n }\n const getter = property && property.get\n const setter = property && property.set\n if ((!getter || setter) && arguments.length === 2) {\n val = data[key]\n }\n let childOb = observe(val)\n Object.defineProperty(data, key, {\n get: () => {\n const value = getter ? getter.call(data) : val\n if (Dep.target) {\n dep.addSub(Dep.target)\n if (childOb) {\n childOb.dep.addSub(Dep.target)\n }\n }\n return value\n },\n set: (newVal) => {\n if (newVal === val) return\n val = newVal\n if (getter && !setter) return\n if (setter) {\n setter.call(data, newVal)\n } else {\n val = newVal\n }\n childOb = observe(newVal)\n dep.notify()\n }\n })\n}\n","import Lucky from '../lib/lucky'\nimport Dep from './dep'\nimport { parsePath, traverse } from './utils'\n\nexport interface WatchOptType {\n handler?: () => Function\n immediate?: boolean\n deep?: boolean\n}\n\nlet uid = 0\nexport default class Watcher {\n id: number\n $lucky: Lucky\n expr: string | Function\n cb: Function\n deep: boolean\n getter: Function\n value: any\n\n /**\n * 观察者构造器\n * @param {*} $lucky \n * @param {*} expr \n * @param {*} cb \n */\n constructor ($lucky: Lucky, expr: string | Function, cb: Function, options: WatchOptType = {}) {\n this.id = uid++\n this.$lucky = $lucky\n this.expr = expr\n this.deep = !!options.deep\n if (typeof expr === 'function') {\n this.getter = expr\n } else {\n this.getter = parsePath(expr)\n }\n this.cb = cb\n this.value = this.get()\n }\n\n /**\n * 根据表达式获取新值\n */\n get () {\n Dep.target = this\n const value = this.getter.call(this.$lucky, this.$lucky)\n // 处理深度监听\n if (this.deep) {\n traverse(value)\n }\n Dep.target = null\n return value\n }\n\n /**\n * 触发 watcher 更新\n */\n update () {\n // get获取新值\n const newVal = this.get()\n // 读取之前存储的旧值\n const oldVal = this.value\n this.value = newVal\n // 触发 watch 回调\n this.cb.call(this.$lucky, newVal, oldVal)\n }\n}\n","import '../utils/polyfill'\nimport { has, isExpectType, throttle } from '../utils/index'\nimport { name, version } from '../../package.json'\nimport { ConfigType, UserConfigType, ImgItemType, ImgType, Tuple } from '../types/index'\nimport { defineReactive } from '../observer'\nimport Watcher, { WatchOptType } from '../observer/watcher'\n\nexport default class Lucky {\n static version: string = version\n protected readonly version: string = version\n protected readonly config: ConfigType\n protected readonly ctx: CanvasRenderingContext2D\n protected htmlFontSize: number = 16\n protected rAF: Function = function () {}\n protected boxWidth: number = 0\n protected boxHeight: number = 0\n protected data: {\n width: string | number,\n height: string | number\n }\n\n /**\n * 公共构造器\n * @param config\n */\n constructor (\n config: string | HTMLDivElement | UserConfigType,\n data: {\n width: string | number,\n height: string | number\n }\n ) {\n // 兼容代码开始: 为了处理 v1.0.6 版本在这里传入了一个 dom\n if (typeof config === 'string') config = { el: config } as UserConfigType\n else if (config.nodeType === 1) config = { el: '', divElement: config } as UserConfigType\n // 这里先野蛮的处理, 等待后续优化, 对外暴露的类型是UserConfigType, 但内部期望是ConfigType\n config = config as UserConfigType\n this.config = config as ConfigType\n this.data = data\n // 开始初始化\n if (!config.flag) config.flag = 'WEB'\n if (config.el) config.divElement = document.querySelector(config.el) as HTMLDivElement\n // 如果存在父盒子, 就创建canvas标签\n if (config.divElement) {\n // 无论盒子内有没有canvas都执行覆盖逻辑\n config.canvasElement = document.createElement('canvas')\n config.divElement.appendChild(config.canvasElement)\n }\n // 获取 canvas 上下文\n if (config.canvasElement) {\n config.ctx = config.canvasElement.getContext('2d')!\n // 添加版本信息到标签上, 方便定位版本问题\n config.canvasElement.setAttribute('package', `${name}@${version}`)\n config.canvasElement.addEventListener('click', e => this.handleClick(e))\n }\n this.ctx = config.ctx as CanvasRenderingContext2D\n // 初始化 window 方法\n this.initWindowFunction()\n // 如果最后得不到 canvas 上下文那就无法进行绘制\n if (!this.config.ctx) {\n console.error('无法获取到 CanvasContext2D')\n }\n // 监听 window 触发 resize 时重置\n if (window && typeof window.addEventListener === 'function') {\n window.addEventListener('resize', throttle(() => this.resize(), 300))\n }\n // 监听异步设置 html 的 fontSize 并重新绘制\n if (window && typeof window.MutationObserver === 'function') {\n new window.MutationObserver(() => {\n this.resize()\n }).observe(document.documentElement, { attributes: true })\n }\n }\n\n /**\n * 初始化组件大小/单位\n */\n protected resize(): void {\n this.config.beforeResize?.()\n // 先初始化 fontSize 以防后面有 rem 单位\n this.setHTMLFontSize()\n // 拿到 config 即可设置 dpr\n this.setDpr()\n // 初始化宽高\n this.resetWidthAndHeight()\n // 根据 dpr 来缩放 canvas\n this.zoomCanvas()\n }\n\n /**\n * 初始化方法\n */\n protected initLucky () {\n this.resize()\n if (!this.boxWidth || !this.boxHeight) {\n return console.error('无法获取到宽度或高度')\n }\n }\n\n /**\n * 鼠标点击事件\n * @param e 事件参数\n */\n protected handleClick (e: MouseEvent): void {}\n\n /**\n * 根标签的字体大小\n */\n protected setHTMLFontSize (): void {\n if (!window) return\n this.htmlFontSize = +window.getComputedStyle(document.documentElement).fontSize.slice(0, -2)\n }\n\n // 清空画布\n public clearCanvas (): void {\n const [width, height] = [this.boxWidth, this.boxHeight]\n this.ctx.clearRect(-width, -height, width * 2, height * 2)\n }\n\n /**\n * 设备像素比\n * window 环境下自动获取, 其余环境手动传入\n */\n protected setDpr (): void {\n const { config } = this\n if (config.dpr) {\n // 优先使用 config 传入的 dpr\n } else if (window) {\n window['dpr'] = config.dpr = window.devicePixelRatio || 1\n } else if (!config.dpr) {\n console.error(config, '未传入 dpr 可能会导致绘制异常')\n }\n }\n\n /**\n * 重置盒子和canvas的宽高\n */\n private resetWidthAndHeight (): void {\n const { config, data } = this\n // 如果是浏览器环境并且存在盒子\n let boxWidth = 0, boxHeight = 0\n if (config.divElement) {\n boxWidth = config.divElement.offsetWidth\n boxHeight = config.divElement.offsetHeight\n }\n // 先从 data 里取宽高, 如果 config 上面没有, 就从 style 上面取\n this.boxWidth = this.getLength(data.width || config['width']) || boxWidth\n this.boxHeight = this.getLength(data.height || config['height']) || boxHeight\n // 重新把宽高赋给盒子\n if (config.divElement) {\n config.divElement.style.overflow = 'hidden'\n config.divElement.style.width = this.boxWidth + 'px'\n config.divElement.style.height = this.boxHeight + 'px'\n }\n }\n\n /**\n * 根据 dpr 缩放 canvas 并处理位移\n */\n protected zoomCanvas (): void {\n const { config, ctx } = this\n const { canvasElement, dpr } = config\n const [width, height] = [this.boxWidth * dpr, this.boxHeight * dpr]\n if (!canvasElement) return\n canvasElement.width = width\n canvasElement.height = height\n canvasElement.style.width = `${width}px`\n canvasElement.style.height = `${height}px`\n canvasElement.style['transform-origin'] = 'left top'\n canvasElement.style.transform = `scale(${1 / dpr})`\n ctx.scale(dpr, dpr)\n }\n\n /**\n * 从 window 对象上获取一些方法\n */\n private initWindowFunction (): void {\n const { config } = this\n if (window) {\n this.rAF = window.requestAnimationFrame ||\n window['webkitRequestAnimationFrame'] ||\n window['mozRequestAnimationFrame'] ||\n function (callback: Function) {\n window.setTimeout(callback, 1000 / 60)\n }\n config.setTimeout = window.setTimeout\n config.setInterval = window.setInterval\n config.clearTimeout = window.clearTimeout\n config.clearInterval = window.clearInterval\n return\n }\n if (config.rAF) {\n // 优先使用帧动画\n this.rAF = config.rAF\n } else if (config.setTimeout) {\n // 其次使用定时器\n const timeout = config.setTimeout\n this.rAF = (callback: Function): number => timeout(callback, 16.7)\n } else {\n // 如果config里面没有提供, 那就假设全局方法存在setTimeout\n this.rAF = (callback: Function): number => setTimeout(callback, 16.7)\n }\n }\n\n public isWeb () {\n return ['WEB', 'UNI-H5', 'TARO-H5'].includes(this.config.flag)\n }\n\n /**\n * 异步加载图片并返回图片的几何信息\n * @param src 图片路径\n * @param info 图片信息\n */\n protected loadImg (\n src: string,\n info: ImgItemType,\n resolveName = '$resolve'\n ): Promise<ImgType> {\n return new Promise((resolve, reject) => {\n if (!src) reject(`=> '${info.src}' 不能为空或不合法`)\n if (this.config.flag === 'WEB') {\n let imgObj = new Image()\n imgObj['crossorigin'] = 'anonymous'\n imgObj.onload = () => resolve(imgObj)\n imgObj.onerror = () => reject(`=> '${info.src}' 图片加载失败`)\n imgObj.src = src\n } else {\n // 其余平台向外暴露, 交给外部自行处理\n info[resolveName] = resolve\n info['$reject'] = reject\n return\n }\n })\n }\n\n /**\n * 公共绘制图片的方法\n * @param imgObj 图片对象\n * @param rectInfo: [x轴位置, y轴位置, 渲染宽度, 渲染高度] \n */\n protected drawImage(\n ctx: CanvasRenderingContext2D,\n imgObj: ImgType,\n ...rectInfo: [...Tuple<number, 4>, ...Partial<Tuple<number, 4>>]\n ): void {\n let drawImg\n const { flag, dpr } = this.config\n if (['WEB', 'MP-WX'].includes(flag)) {\n // 浏览器和新版小程序中直接绘制即可\n drawImg = imgObj\n } else if (['UNI-H5', 'UNI-MP', 'TARO-H5', 'TARO-MP'].includes(flag)) {\n // 旧版本的小程序需要绘制 path, 这里特殊处理一下\n type OldImageType = ImgType & { path: CanvasImageSource }\n drawImg = (imgObj as OldImageType).path\n } else {\n // 如果传入了未知的标识\n return console.error('意料之外的 flag, 该平台尚未兼容!')\n }\n const miniProgramOffCtx = (drawImg['canvas'] || drawImg).getContext?.('2d')\n if (miniProgramOffCtx && !this.isWeb()) {\n rectInfo = rectInfo.map(val => val! * dpr) as Tuple<number, 8>\n const temp = miniProgramOffCtx.getImageData(...rectInfo.slice(0, 4))\n ctx.putImageData(temp, ...(rectInfo.slice(4, 6) as Tuple<number, 2>))\n } else {\n if (rectInfo.length === 8) {\n rectInfo = rectInfo.map((val, index) => index < 4 ? val! * dpr : val) as Tuple<number, 8>\n }\n // 尝试捕获错误\n try {\n ctx.drawImage(drawImg, ...rectInfo as Tuple<number, 8>)\n } catch (err) {\n /**\n * TODO: safari浏览器下, init() 会出现奇怪的报错\n * IndexSizeError: The index is not in the allowed range\n * 但是这个报错并不影响实际的绘制, 目前先放一放, 等待有缘人\n */\n // console.log(err)\n }\n }\n }\n\n /**\n * 计算图片的渲染宽高\n * @param imgObj 图片标签元素\n * @param imgInfo 图片信息\n * @param maxWidth 最大宽度\n * @param maxHeight 最大高度\n * @return [渲染宽度, 渲染高度]\n */\n protected computedWidthAndHeight (\n imgObj: ImgType,\n imgInfo: ImgItemType,\n maxWidth: number,\n maxHeight: number\n ): [number, number] {\n // 根据配置的样式计算图片的真实宽高\n if (!imgInfo.width && !imgInfo.height) {\n // 如果没有配置宽高, 则使用图片本身的宽高\n return [imgObj.width, imgObj.height]\n } else if (imgInfo.width && !imgInfo.height) {\n // 如果只填写了宽度, 没填写高度\n let trueWidth = this.getLength(imgInfo.width, maxWidth)\n // 那高度就随着宽度进行等比缩放\n return [trueWidth, imgObj.height * (trueWidth / imgObj.width)]\n } else if (!imgInfo.width && imgInfo.height) {\n // 如果只填写了宽度, 没填写高度\n let trueHeight = this.getLength(imgInfo.height, maxHeight)\n // 那宽度就随着高度进行等比缩放\n return [imgObj.width * (trueHeight / imgObj.height), trueHeight]\n }\n // 如果宽度和高度都填写了, 就如实计算\n return [\n this.getLength(imgInfo.width, maxWidth),\n this.getLength(imgInfo.height, maxHeight)\n ]\n }\n\n /**\n * 转换单位\n * @param { string } value 将要转换的值\n * @param { number } denominator 分子\n * @return { number } 返回新的字符串\n */\n protected changeUnits (value: string, denominator = 1): number {\n const { config } = this\n return Number(value.replace(/^([-]*[0-9.]*)([a-z%]*)$/, (val, num, unit) => {\n const handleCssUnit = {\n '%': (n: number) => n * (denominator / 100),\n 'px': (n: number) => n * 1,\n 'rem': (n: number) => n * this.htmlFontSize,\n 'vw': (n: number) => n / 100 * window.innerWidth,\n }[unit]\n if (handleCssUnit) return handleCssUnit(num)\n // 如果找不到默认单位, 就交给外面处理\n const otherHandleCssUnit = config.handleCssUnit || config['unitFunc']\n return otherHandleCssUnit ? otherHandleCssUnit(num, unit) : num\n }))\n }\n\n /**\n * 获取长度\n * @param length 将要转换的长度\n * @param maxLength 最大长度\n * @return 返回长度\n */\n protected getLength (length: string | number | undefined, maxLength?: number): number {\n if (isExpectType(length, 'number')) return length as number\n if (isExpectType(length, 'string')) return this.changeUnits(length as string, maxLength)\n return 0\n }\n\n /**\n * 获取相对(居中)X坐标\n * @param width\n * @param col\n */\n protected getOffsetX (width: number, maxWidth: number = 0): number {\n return (maxWidth - width) / 2\n }\n\n protected getOffscreenCanvas (width: number, height: number): {\n _offscreenCanvas: HTMLCanvasElement,\n _ctx: CanvasRenderingContext2D\n } | void {\n if (!has(this, '_offscreenCanvas')) {\n if (window && window.document && this.config.flag === 'WEB') {\n this['_offscreenCanvas'] = document.createElement('canvas')\n } else {\n this['_offscreenCanvas'] = this.config['offscreenCanvas']\n }\n if (!this['_offscreenCanvas']) return console.error('离屏 Canvas 无法渲染!')\n }\n const dpr = this.config.dpr\n const _offscreenCanvas = this['_offscreenCanvas'] as HTMLCanvasElement\n _offscreenCanvas.width = (width || 300) * dpr\n _offscreenCanvas.height = (height || 150) * dpr\n const _ctx = _offscreenCanvas.getContext('2d')!\n _ctx.clearRect(0, 0, width, height)\n _ctx.scale(dpr, dpr)\n _ctx['dpr'] = dpr\n return { _offscreenCanvas, _ctx }\n }\n\n /**\n * 添加一个新的响应式数据 (临时)\n * @param data 数据\n * @param key 属性\n * @param value 新值\n */\n public $set (data: object, key: string | number, value: any) {\n if (!data || typeof data !== 'object') return\n defineReactive(data, key, value)\n }\n\n /**\n * 添加一个属性计算 (临时)\n * @param data 源数据\n * @param key 属性名\n * @param callback 回调函数\n */\n protected $computed (data: object, key: string, callback: Function) {\n Object.defineProperty(data, key, {\n get: () => {\n return callback.call(this)\n }\n })\n }\n\n /**\n * 添加一个观察者 create user watcher\n * @param expr 表达式\n * @param handler 回调函数\n * @param watchOpt 配置参数\n * @return 卸载当前观察者的函数 (暂未返回)\n */\n protected $watch (\n expr: string | Function,\n handler: Function | WatchOptType,\n watchOpt: WatchOptType = {}\n ): Function {\n if (typeof handler === 'object') {\n watchOpt = handler\n handler = watchOpt.handler!\n }\n // 创建 user watcher\n const watcher = new Watcher(this, expr, handler, watchOpt)\n // 判断是否需要初始化时触发回调\n if (watchOpt.immediate) {\n handler.call(this, watcher.value)\n }\n // 返回一个卸载当前观察者的函数\n return function unWatchFn () {}\n }\n}\n","/**\n * 转换为运算角度\n * @param { number } deg 数学角度\n * @return { number } 运算角度\n */\nexport const getAngle = (deg: number): number => {\n return Math.PI / 180 * deg\n}\n\n/**\n * 根据角度计算圆上的点\n * @param { number } deg 运算角度\n * @param { number } r 半径\n * @return { Array<number> } 坐标[x, y]\n */\nexport const getArcPointerByDeg = (deg: number, r: number): [number, number] => {\n return [+(Math.cos(deg) * r).toFixed(8), +(Math.sin(deg) * r).toFixed(8)]\n}\n\n/**\n * 根据点计算切线方程\n * @param { number } x 横坐标\n * @param { number } y 纵坐标\n * @return { Array<number> } [斜率, 常数]\n */\nexport const getTangentByPointer = (x: number, y: number): Array<number> => {\n let k = - x / y\n let b = -k * x + y\n return [k, b]\n}\n\n// 使用 arc 绘制扇形\nexport const fanShapedByArc = (\n ctx: CanvasRenderingContext2D,\n minRadius: number,\n maxRadius: number,\n start: number,\n end: number,\n gutter: number,\n): void => {\n ctx.beginPath()\n let maxGutter = getAngle(90 / Math.PI / maxRadius * gutter)\n let minGutter = getAngle(90 / Math.PI / minRadius * gutter)\n let maxStart = start + maxGutter\n let maxEnd = end - maxGutter\n let minStart = start + minGutter\n let minEnd = end - minGutter\n ctx.arc(0, 0, maxRadius, maxStart, maxEnd, false)\n // 如果 getter 比按钮短就绘制圆弧, 反之计算新的坐标点\n // if (minEnd > minStart) {\n // ctx.arc(0, 0, minRadius, minEnd, minStart, true)\n // } else {\n ctx.lineTo(\n ...getArcPointerByDeg(\n (start + end) / 2,\n gutter / 2 / Math.abs(Math.sin((start - end) / 2))\n )\n )\n // }\n ctx.closePath()\n}\n\n// 使用 arc 绘制圆角矩形\nexport const roundRectByArc = (\n ctx: CanvasRenderingContext2D,\n ...[x, y, w, h, r]: number[]\n) => {\n const min = Math.min(w, h), PI = Math.PI\n if (r > min / 2) r = min / 2\n ctx.beginPath()\n ctx.moveTo(x + r, y)\n ctx.lineTo(x + r, y)\n ctx.lineTo(x + w - r, y)\n ctx.arc(x + w - r, y + r, r, -PI / 2, 0)\n ctx.lineTo(x + w, y + h - r)\n ctx.arc(x + w - r, y + h - r, r, 0, PI / 2)\n ctx.lineTo(x + r, y + h)\n ctx.arc(x + r, y + h - r, r, PI / 2, PI)\n ctx.lineTo(x, y + r)\n ctx.arc(x + r, y + r, r, PI, -PI / 2)\n ctx.closePath()\n}\n\n/**\n * 创建线性渐变色\n */\nexport const getLinearGradient = (\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n w: number,\n h: number,\n background: string\n) => {\n const context = (/linear-gradient\\((.+)\\)/.exec(background) as Array<any>)[1]\n .split(',') // 根据逗号分割\n .map((text: string) => text.trim()) // 去除两边空格\n let deg = context.shift(), direction: [number, number, number, number] = [0, 0, 0, 0]\n // 通过起始点和角度计算渐变终点的坐标点, 这里感谢泽宇大神提醒我使用勾股定理....\n if (deg.includes('deg')) {\n deg = deg.slice(0, -3) % 360\n // 根据4个象限定义起点坐标, 根据45度划分8个区域计算终点坐标\n const getLenOfTanDeg = (deg: number) => Math.tan(deg / 180 * Math.PI)\n if (deg >= 0 && deg < 45) direction = [x, y + h, x + w, y + h - w * getLenOfTanDeg(deg - 0)]\n else if (deg >= 45 && deg < 90) direction = [x, y + h, (x + w) - h * getLenOfTanDeg(deg - 45), y]\n else if (deg >= 90 && deg < 135) direction = [x + w, y + h, (x + w) - h * getLenOfTanDeg(deg - 90), y]\n else if (deg >= 135 && deg < 180) direction = [x + w, y + h, x, y + w * getLenOfTanDeg(deg - 135)]\n else if (deg >= 180 && deg < 225) direction = [x + w, y, x, y + w * getLenOfTanDeg(deg - 180)]\n else if (deg >= 225 && deg < 270) direction = [x + w, y, x + h * getLenOfTanDeg(deg - 225), y + h]\n else if (deg >= 270 && deg < 315) direction = [x, y, x + h * getLenOfTanDeg(deg - 270), y + h]\n else if (deg >= 315 && deg < 360) direction = [x, y, x + w, y + h - w * getLenOfTanDeg(deg - 315)]\n }\n // 创建四个简单的方向坐标\n else if (deg.includes('top')) direction = [x, y + h, x, y]\n else if (deg.includes('bottom')) direction = [x, y, x, y + h]\n else if (deg.includes('left')) direction = [x + w, y, x, y]\n else if (deg.includes('right')) direction = [x, y, x + w, y]\n // 创建线性渐变必须使用整数坐标\n const gradient = ctx.createLinearGradient(...(direction.map(n => n >> 0) as typeof direction))\n // 这里后期重构, 先用any代替\n return context.reduce((gradient: any, item: any, index: any) => {\n const info = item.split(' ')\n if (info.length === 1) gradient.addColorStop(index, info[0])\n else if (info.length === 2) gradient.addColorStop(...info)\n return gradient\n }, gradient)\n}\n\n// // 根据三点画圆弧\n// export const drawRadian = (\n// ctx: CanvasRenderingContext2D,\n// r: number,\n// start: number,\n// end: number,\n// direction: boolean = true\n// ) => {\n// // 如果角度大于等于180度, 则分两次绘制, 因为 arcTo 无法绘制180度的圆弧\n// if (Math.abs(end - start).toFixed(8) >= getAngle(180).toFixed(8)) {\n// let middle = (end + start) / 2\n// if (direction) {\n// drawRadian(ctx, r, start, middle, direction)\n// drawRadian(ctx, r, middle, end, direction)\n// } else {\n// drawRadian(ctx, r, middle, end, direction)\n// drawRadian(ctx, r, start, middle, direction)\n// }\n// return false\n// }\n// // 如果方法相反, 则交换起点和终点\n// if (!direction) [start, end] = [end, start]\n// const [x1, y1] = getArcPointerByDeg(start, r)\n// const [x2, y2] = getArcPointerByDeg(end, r)\n// const [k1, b1] = getTangentByPointer(x1, y1)\n// const [k2, b2] = getTangentByPointer(x2, y2)\n// // 计算两条切线的交点\n// let x0 = (b2 - b1) / (k1 - k2)\n// let y0 = (k2 * b1 - k1 * b2) / (k2 - k1)\n// // 如果有任何一条切线垂直于x轴, 则斜率不存在\n// if (isNaN(x0)) {\n// Math.abs(x1) === +r.toFixed(8) && (x0 = x1)\n// Math.abs(x2) === +r.toFixed(8) && (x0 = x2)\n// }\n// if (k1 === Infinity || k1 === -Infinity) {\n// y0 = k2 * x0 + b2\n// }\n// else if (k2 === Infinity || k2 === -Infinity) {\n// y0 = k1 * x0 + b1\n// }\n// ctx.lineTo(x1, y1)\n// // 微信小程序下 arcTo 在安卓真机下绘制有 bug\n// ctx.arcTo(x0, y0, x2, y2, r)\n// }\n\n// // 使用 arcTo 绘制扇形 (弃用)\n// export const drawSectorByArcTo = (\n// ctx: CanvasRenderingContext2D,\n// minRadius: number,\n// maxRadius: number,\n// start: number,\n// end: number,\n// gutter: number,\n// ) => {\n// if (!minRadius) minRadius = gutter\n// // 内外圆弧分别进行等边缩放\n// let maxGutter = getAngle(90 / Math.PI / maxRadius * gutter)\n// let minGutter = getAngle(90 / Math.PI / minRadius * gutter)\n// let maxStart = start + maxGutter\n// let maxEnd = end - maxGutter\n// let minStart = start + minGutter\n// let minEnd = end - minGutter\n// ctx.beginPath()\n// ctx.moveTo(...getArcPointerByDeg(maxStart, maxRadius))\n// drawRadian(ctx, maxRadius, maxStart, maxEnd, true)\n// // 如果 getter 比按钮短就绘制圆弧, 反之计算新的坐标点\n// if (minEnd > minStart) {\n// drawRadian(ctx, minRadius, minStart, minEnd, false)\n// } else {\n// ctx.lineTo(\n// ...getArcPointerByDeg(\n// (start + end) / 2,\n// gutter / 2 / Math.abs(Math.sin((start - end) / 2))\n// )\n// )\n// }\n// ctx.closePath()\n// }\n\n// // 使用 arcTo 绘制圆角矩形 (弃用)\n// export const roundRectByArcTo = (\n// ctx: CanvasRenderingContext2D,\n// ...[x, y, w, h, r]: number[]\n// ) => {\n// let min = Math.min(w, h)\n// if (r > min / 2) r = min / 2\n// ctx.beginPath()\n// ctx.moveTo(x + r, y)\n// ctx.lineTo(x + r, y)\n// ctx.lineTo(x + w - r, y)\n// ctx.arcTo(x + w, y, x + w, y + r, r)\n// ctx.lineTo(x + w, y + h - r)\n// ctx.arcTo(x + w, y + h, x + w - r, y + h, r)\n// ctx.lineTo(x + r, y + h)\n// ctx.arcTo(x, y + h, x, y + h - r, r)\n// ctx.lineTo(x, y + r)\n// ctx.arcTo(x, y, x + r, y, r)\n// }\n","/**\n * 缓动函数\n * t: current time(当前时间)\n * b: beginning value(初始值)\n * c: change in value(变化量)\n * d: duration(持续时间)\n * \n * 感谢张鑫旭大佬 https://github.com/zhangxinxu/Tween\n */\n\ninterface SpeedType {\n easeIn: (...arr: number[]) => number\n easeOut: (...arr: number[]) => number\n}\n\n// 二次方的缓动\nexport const quad: SpeedType = {\n easeIn: function (t, b, c, d) {\n if (t >= d) t = d\n return c * (t /= d) * t + b\n },\n easeOut: function (t, b, c, d) {\n if (t >= d) t = d\n return -c * (t /= d) * (t - 2) + b\n }\n}\n\n// 三次方的缓动\nexport const cubic: SpeedType = {\n easeIn: function (t, b, c, d) {\n if (t >= d) t = d\n return c * (t /= d) * t * t + b\n },\n easeOut: function (t, b, c, d) {\n if (t >= d) t = d\n return c * ((t = t / d - 1) * t * t + 1) + b\n }\n}\n\n// 四次方的缓动\nexport const quart: SpeedType = {\n easeIn: function (t, b, c, d) {\n if (t >= d) t = d\n return c * (t /= d) * t * t * t + b\n },\n easeOut: function (t, b, c, d) {\n if (t >= d) t = d\n return -c * ((t = t / d - 1) * t * t * t - 1) + b\n }\n}\n\n// 五次方的缓动\nexport const quint: SpeedType = {\n easeIn: function (t, b, c, d) {\n if (t >= d) t = d\n return c * (t /= d) * t * t * t * t + b\n },\n easeOut: function (t, b, c, d) {\n if (t >= d) t = d\n return c * ((t = t / d - 1) * t * t * t * t + 1) + b\n }\n}\n\n// 正弦曲线的缓动\nexport const sine: SpeedType = {\n easeIn: function (t, b, c, d) {\n if (t >= d) t = d\n return -c * Math.cos(t / d * (Math.PI / 2)) + c + b\n },\n easeOut: function (t, b, c, d) {\n if (t >= d) t = d\n return c * Math.sin(t / d * (Math.PI / 2)) + b\n }\n}\n\n// 指数曲线的缓动\nexport const expo: SpeedType = {\n easeIn: function (t, b, c, d) {\n if (t >= d) t = d\n return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b\n },\n easeOut: function (t, b, c, d) {\n if (t >= d) t = d\n return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b\n }\n}\n\n// 圆形曲线的缓动\nexport const circ: SpeedType = {\n easeIn: function (t, b, c, d) {\n if (t >= d) t = d\n return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b\n },\n easeOut: function (t, b, c, d) {\n if (t >= d) t = d\n return c * Math.sqrt(1 - (t = t / d - 1) * t) + b\n }\n}\n","import Lucky from './lucky'\nimport { UserConfigType, FontItemType, ImgType } from '../types/index'\nimport LuckyWheelConfig, {\n BlockType,\n PrizeType,\n ButtonType,\n DefaultConfigType,\n DefaultStyleType,\n StartCallbackType,\n EndCallbackType\n} from '../types/wheel'\nimport {\n removeEnter,\n hasBackground,\n computeRange,\n splitText,\n has,\n} from '../utils/index'\nimport { getAngle, fanShapedByArc } from '../utils/math'\nimport { quad } from '../utils/tween'\n\nexport default class LuckyWheel extends Lucky {\n private blocks: Array<BlockType> = []\n private prizes: Array<PrizeType> = []\n private buttons: Array<ButtonType> = []\n private defaultConfig: DefaultConfigType = {}\n private defaultStyle: DefaultStyleType = {}\n private _defaultConfig: Required<DefaultConfigType> = {} as Required<DefaultConfigType>\n private _defaultStyle: Required<DefaultStyleType> = {} as Required<DefaultStyleType>\n private startCallback?: StartCallbackType\n private endCallback?: EndCallbackType\n private Radius = 0 // 大转盘半径\n private prizeRadius = 0 // 奖品区域半径\n private prizeDeg = 0 // 奖品数学角度\n private prizeAng = 0 // 奖品运算角度\n private rotateDeg = 0 // 转盘旋转角度\n private maxBtnRadius = 0 // 最大按钮半径\n private startTime = 0 // 开始时间戳\n private endTime = 0 // 停止时间戳\n private stopDeg = 0 // 刻舟求剑\n private endDeg = 0 // 停止角度\n private FPS = 16.6 // 屏幕刷新率\n /**\n * 游戏当前的阶段\n * step = 0 时, 游戏尚未开始\n * step = 1 时, 此时处于加速阶段\n * step = 2 时, 此时处于匀速阶段\n * step = 3 时, 此时处于减速阶段\n */\n private step: 0 | 1 | 2 | 3 = 0\n /**\n * 中奖索引\n * prizeFlag = undefined 时, 处于开始抽奖阶段, 正常旋转\n * prizeFlag >= 0 时, 说明stop方法被调用, 并且传入了中奖索引\n * prizeFlag === -1 时, 说明stop方法被调用, 并且传入了负值, 本次抽奖无效\n */\n private prizeFlag: number | undefined\n private ImageCache = new Map()\n\n /**\n * 大转盘构造器\n * @param config 配置项\n * @param data 抽奖数据\n */\n constructor (config: UserConfigType, data: LuckyWheelConfig) {\n super(config, {\n width: data.width,\n height: data.height\n })\n this.initData(data)\n this.initWatch()\n this.initComputed()\n // 创建前回调函数\n config.beforeCreate?.call(this)\n // 首次初始化\n this.init()\n }\n\n protected resize(): void {\n super.resize()\n this.Radius = Math.min(this.boxWidth, this.boxHeight) / 2\n this.ctx.translate(this.Radius, this.Radius)\n this.draw()\n this.config.afterResize?.()\n }\n\n protected initLucky (): void {\n this.Radius = 0\n this.prizeRadius = 0\n this.prizeDeg = 0\n this.prizeAng = 0\n this.rotateDeg = 0\n this.maxBtnRadius = 0\n this.startTime = 0\n this.endTime = 0\n this.stopDeg = 0\n this.endDeg = 0\n this.FPS = 16.6\n this.prizeFlag = -1\n this.step = 0\n super.initLucky()\n }\n\n /**\n * 初始化数据\n * @param data\n */\n private initData (data: LuckyWheelConfig): void {\n this.$set(this, 'width', data.width)\n this.$set(this, 'height', data.height)\n this.$set(this, 'blocks', data.blocks || [])\n this.$set(this, 'prizes', data.prizes || [])\n this.$set(this, 'buttons', data.buttons || [])\n this.$set(this, 'defaultConfig', data.defaultConfig || {})\n this.$set(this, 'defaultStyle', data.defaultStyle || {})\n this.$set(this, 'startCallback', data.start)\n this.$set(this, 'endCallback', data.end)\n }\n\n /**\n * 初始化属性计算\n */\n private initComputed () {\n // 默认配置\n this.$computed(this, '_defaultConfig', () => {\n const config = {\n gutter: '0px',\n offsetDegree: 0,\n speed: 20,\n speedFunction: 'quad',\n accelerationTime: 2500,\n decelerationTime: 2500,\n stopRange: 0,\n ...this.defaultConfig\n }\n return config\n })\n // 默认样式\n this.$computed(this, '_defaultStyle', () => {\n const style = {\n fontSize: '18px',\n fontColor: '#000',\n fontStyle: 'sans-serif',\n fontWeight: '400',\n background: 'rgba(0,0,0,0)',\n wordWrap: true,\n lengthLimit: '90%',\n ...this.defaultStyle\n }\n return style\n })\n }\n\n /**\n * 初始化观察者\n */\n private initWatch () {\n // 重置宽度\n this.$watch('width', (newVal: string | number) => {\n this.data.width = newVal\n this.resize()\n })\n // 重置高度\n this.$watch('height', (newVal: string | number) => {\n this.data.height = newVal\n this.resize()\n })\n // 观察 blocks 变化收集图片\n this.$watch('blocks', (newData: Array<BlockType>) => {\n this.initImageCache()\n }, { deep: true })\n // 观察 prizes 变化收集图片\n this.$watch('prizes', (newData: Array<PrizeType>) => {\n this.initImageCache()\n }, { deep: true })\n // 观察 buttons 变化收集图片\n this.$watch('buttons', (newData: Array<ButtonType>) => {\n this.initImageCache()\n }, { deep: true })\n this.$watch('defaultConfig', () => this.draw(), { deep: true })\n this.$watch('defaultStyle', () => this.draw(), { deep: true })\n this.$watch('startCallback', () => this.init())\n this.$watch('endCallback', () => this.init())\n }\n\n /**\n * 初始化 canvas 抽奖\n */\n public async init (): Promise<void> {\n this.initLucky()\n const { config } = this\n // 初始化前回调函数\n config.beforeInit?.call(this)\n this.draw() // 先画一次, 防止闪烁\n this.draw() // 再画一次, 拿到正确的按钮轮廓\n // 异步加载图片\n await this.initImageCache()\n // 初始化后回调函数\n config.afterInit?.call(this)\n }\n\n private initImageCache (): Promise<void> {\n return new Promise((resolve) => {\n const willUpdateImgs = {\n blocks: this.blocks.map(block => block.imgs),\n prizes: this.prizes.map(prize => prize.imgs),\n buttons: this.buttons.map(btn => btn.imgs),\n }\n ;(<(keyof typeof willUpdateImgs)[]>Object.keys(willUpdateImgs)).forEach(imgName => {\n const willUpdate = willUpdateImgs[imgName]\n // 循环遍历所有图片\n const allPromise: Promise<void>[] = []\n willUpdate && willUpdate.forEach((imgs, cellIndex) => {\n imgs && imgs.forEach((imgInfo, imgIndex) => {\n allPromise.push(this.loadAndCacheImg(imgName, cellIndex, imgIndex))\n })\n })\n Promise.all(allPromise).then(() => {\n this.draw()\n resolve()\n })\n })\n })\n }\n\n /**\n * canvas点击事件\n * @param e 事件参数\n */\n protected handleClick (e: MouseEvent): void {\n const { ctx } = this\n ctx.beginPath()\n ctx.arc(0, 0, this.maxBtnRadius, 0, Math.PI * 2, false)\n if (!ctx.isPointInPath(e.offsetX, e.offsetY)) return\n if (this.step !== 0) return\n this.startCallback?.(e)\n }\n\n /**\n * 根据索引单独加载指定图片并缓存\n * @param cellName 模块名称\n * @param cellIndex 模块索引\n * @param imgName 模块对应的图片缓存\n * @param imgIndex 图片索引\n */\n private async loadAndCacheImg (\n cellName: 'blocks' | 'prizes' | 'buttons',\n cellIndex: number,\n imgIndex: number,\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n // 获取图片信息\n const cell: BlockType | PrizeType | ButtonType = this[cellName][cellIndex]\n if (!cell || !cell.imgs) return\n const imgInfo = cell.imgs[imgIndex]\n if (!imgInfo) return\n // 异步加载图片\n this.loadImg(imgInfo.src, imgInfo).then(async currImg => {\n if (typeof imgInfo.formatter === 'function') {\n currImg = await Promise.resolve(imgInfo.formatter.call(this, currImg))\n }\n this.ImageCache.set(imgInfo['src'], currImg)\n resolve()\n }).catch(err => {\n console.error(`${cellName}[${cellIndex}].imgs[${imgIndex}] ${err}`)\n reject()\n })\n })\n }\n\n private drawBlock (radius: number, block: BlockType, blockIndex: number): void {\n const { ctx } = this\n if (hasBackground(block.background)) {\n ctx.beginPath()\n ctx.fillStyle = block.background!\n ctx.arc(0, 0, radius, 0, Math.PI * 2, false)\n ctx.fill()\n }\n block.imgs && block.imgs.forEach((imgInfo, imgIndex) => {\n const blockImg = this.ImageCache.get(imgInfo.src)\n if (!blockImg) return\n // 绘制图片\n const [trueWidth, trueHeight] = this.computedWidthAndHeight(blockImg, imgInfo, radius * 2, radius * 2)\n const [xAxis, yAxis] = [this.getOffsetX(trueWidth) + this.getLength(imgInfo.left, radius * 2), this.getLength(imgInfo.top, radius * 2) - radius]\n ctx.save()\n imgInfo.rotate && ctx.rotate(getAngle(this.rotateDeg))\n this.drawImage(ctx, blockImg, xAxis, yAxis, trueWidth, trueHeight)\n ctx.restore()\n })\n }\n\n /**\n * 开始绘制\n */\n protected draw (): void {\n const { config, ctx, _defaultConfig, _defaultStyle } = this\n // 触发绘制前回调\n config.beforeDraw?.call(this, ctx)\n // 清空画布\n ctx.clearRect(-this.Radius, -this.Radius, this.Radius * 2, this.Radius * 2)\n // 计算 padding 并绘制 blocks 边框\n this.prizeRadius = this.blocks.reduce((radius, block, blockIndex) => {\n this.drawBlock(radius, block, blockIndex)\n return radius - this.getLength(block.padding && block.padding.split(' ')[0])\n }, this.Radius)\n // 计算起始弧度\n this.prizeDeg = 360 / this.prizes.length\n this.prizeAng = getAngle(this.prizeDeg)\n const shortSide = this.prizeRadius * Math.sin(this.prizeAng / 2) * 2\n // 起始角度调整到正上方, 并且减去半个扇形角度\n let start = getAngle(this.rotateDeg - 90 + this.prizeDeg / 2 + _defaultConfig.offsetDegree)\n // 计算文字横坐标\n const getFontX = (font: FontItemType, line: string) => {\n return this.getOffsetX(ctx.measureText(line).width) + this.getLength(font.left, shortSide)\n }\n // 计算文字纵坐标\n const getFontY = (font: FontItemType, height: number, lineIndex: number) => {\n // 优先使用字体行高, 要么使用默认行高, 其次使用字体大小, 否则使用默认字体大小\n const lineHeight = font.lineHeight || _defaultStyle.lineHeight || font.fontSize || _defaultStyle.fontSize\n return this.getLength(font.top, height) + (lineIndex + 1) * this.getLength(lineHeight)\n }\n ctx.save()\n // 绘制prizes奖品区域\n this.prizes.forEach((prize, prizeIndex) => {\n // 计算当前奖品区域中间坐标点\n let currMiddleDeg = start + prizeIndex * this.prizeAng\n // 奖品区域可见高度\n let prizeHeight = this.prizeRadius - this.maxBtnRadius\n // 绘制背景\n const background = prize.background || _defaultStyle.background\n if (hasBackground(background)) {\n ctx.fillStyle = background\n fanShapedByArc(\n ctx, this.maxBtnRadius, this.prizeRadius,\n currMiddleDeg - this.prizeAng / 2,\n currMiddleDeg + this.prizeAng / 2,\n this.getLength(_defaultConfig.gutter),\n )\n ctx.fill()\n }\n // 计算临时坐标并旋转文字\n let x = Math.cos(currMiddleDeg) * this.prizeRadius\n let y = Math.sin(currMiddleDeg) * this.prizeRadius\n ctx.translate(x, y)\n ctx.rotate(currMiddleDeg + getAngle(90))\n // 绘制图片\n prize.imgs && prize.imgs.forEach((imgInfo, imgIndex) => {\n const prizeImg = this.ImageCache.get(imgInfo.src)\n if (!prizeImg) return\n const [trueWidth, trueHeight] = this.computedWidthAndHeight(\n prizeImg,\n imgInfo,\n this.prizeAng * this.prizeRadius,\n prizeHeight\n )\n const [xAxis, yAxis] = [\n this.getOffsetX(trueWidth) + this.getLength(imgInfo.left, shortSide),\n this.getLength(imgInfo.top, prizeHeight)\n ]\n this.drawImage(ctx, prizeImg, xAxis, yAxis, trueWidth, trueHeight)\n })\n // 逐行绘制文字\n prize.fonts && prize.fonts.forEach(font => {\n const fontColor = font.fontColor || _defaultStyle.fontColor\n const fontWeight = font.fontWeight || _defaultStyle.fontWeight\n const fontSize = this.getLength(font.fontSize || _defaultStyle.fontSize)\n const fontStyle = font.fontStyle || _defaultStyle.fontStyle\n const wordWrap = has(font, 'wordWrap') ? font.wordWrap : _defaultStyle.wordWrap\n const lengthLimit = font.lengthLimit || _defaultStyle.lengthLimit\n const lineClamp = font.lineClamp || _defaultStyle.lineClamp\n ctx.fillStyle = fontColor\n ctx.font = `${fontWeight} ${fontSize >> 0}px ${fontStyle}`\n let lines = [], text = String(font.text)\n if (wordWrap) {\n lines = splitText(ctx, removeEnter(text), (lines) => {\n // 三角形临边\n const adjacentSide = this.prizeRadius - getFontY(font, prizeHeight, lines.length)\n // 三角形短边\n const shortSide = adjacentSide * Math.tan(this.prizeAng / 2)\n // 最大宽度\n let maxWidth = shortSide * 2 - this.getLength(_defaultConfig.gutter)\n return this.getLength(lengthLimit, maxWidth)\n }, lineClamp)\n } else {\n lines = text.split('\\n')\n }\n lines.filter(line => !!line).forEach((line, lineIndex) => {\n ctx.fillText(line, getFontX(font, line), getFontY(font, prizeHeight, lineIndex))\n })\n })\n // 修正旋转角度和原点坐标\n ctx.rotate(getAngle(360) - currMiddleDeg - getAngle(90))\n ctx.translate(-x, -y)\n })\n ctx.restore()\n // 绘制按钮\n this.buttons.forEach((btn, btnIndex) => {\n let radius = this.getLength(btn.radius, this.prizeRadius)\n // 绘制背景颜色\n this.maxBtnRadius = Math.max(this.maxBtnRadius, radius)\n if (hasBackground(btn.background)) {\n ctx.beginPath()\n ctx.fillStyle = btn.background as string\n ctx.arc(0, 0, radius, 0, Math.PI * 2, false)\n ctx.fill()\n }\n // 绘制指针\n if (btn.pointer && hasBackground(btn.background)) {\n ctx.beginPath()\n ctx.fillStyle = btn.background as string\n ctx.moveTo(-radius, 0)\n ctx.lineTo(radius, 0)\n ctx.lineTo(0, -radius * 2)\n ctx.closePath()\n ctx.fill()\n }\n // 绘制按钮图片\n btn.imgs && btn.imgs.forEach((imgInfo, imgIndex) => {\n const btnImg = this.ImageCache.get(imgInfo.src)\n if (!btnImg) return\n const [trueWidth, trueHeight] = this.computedWidthAndHeight(btnImg, imgInfo, radius * 2, radius * 2)\n const [xAxis, yAxis] = [this.getOffsetX(trueWidth) + this.getLength(imgInfo.left, radius), this.getLength(imgInfo.top, radius)]\n this.drawImage(ctx, btnImg, xAxis, yAxis, trueWidth, trueHeight)\n })\n // 绘制按钮文字\n btn.fonts && btn.fonts.forEach(font => {\n let fontColor = font.fontColor || _defaultStyle.fontColor\n let fontWeight = font.fontWeight || _defaultStyle.fontWeight\n let fontSize = this.getLength(font.fontSize || _defaultStyle.fontSize)\n let fontStyle = font.fontStyle || _defaultStyle.fontStyle\n ctx.fillStyle = fontColor\n ctx.font = `${fontWeight} ${fontSize >> 0}px ${fontStyle}`\n String(font.text).split('\\n').forEach((line, lineIndex) => {\n ctx.fillText(line, getFontX(font, line), getFontY(font, radius, lineIndex))\n })\n })\n })\n // 触发绘制后回调\n config.afterDraw?.call(this, ctx)\n }\n\n /**\n * 刻舟求剑\n */\n private carveOnGunwaleOfAMovingBoat (): void {\n const { _defaultConfig, prizeFlag, prizeDeg, rotateDeg } = this\n this.endTime = Date.now()\n const stopDeg = this.stopDeg = rotateDeg\n const speed = _defaultConfig.speed\n const stopRange = (Math.random() * prizeDeg - prizeDeg / 2) * this.getLength(_defaultConfig.stopRange)\n let i = 0, prevSpeed = 0, prevDeg = 0\n while (++i) {\n const endDeg = 360 * i - prizeFlag! * prizeDeg - rotateDeg - _defaultConfig.offsetDegree + stopRange - prizeDeg / 2\n let currSpeed = quad.easeOut(this.FPS, stopDeg, endDeg, _defaultConfig.decelerationTime) - stopDeg\n if (currSpeed > speed) {\n this.endDeg = (speed - prevSpeed > currSpeed - speed) ? endDeg : prevDeg\n break\n }\n prevDeg = endDeg\n prevSpeed = currSpeed\n }\n }\n\n /**\n * 对外暴露: 开始抽奖方法\n */\n public play (): void {\n if (this.step !== 0) return\n // 记录游戏开始时间\n this.startTime = Date.now()\n // 重置中奖索引\n this.prizeFlag = void 0\n // 加速阶段\n this.step = 1\n // 触发回调\n this.config.afterStart?.()\n // 开始游戏\n this.run()\n }\n\n /**\n * 对外暴露: 缓慢停止方法\n * @param index 中奖索引\n */\n public stop (index?: number): void {\n if (this.step === 0 || this.step === 3) return\n // 如果没有传递中奖索引, 则通过range属性计算一个\n if (!index && index !== 0) {\n const rangeArr = this.prizes.map(item => item.range)\n index = computeRange(rangeArr)\n }\n // 如果index是负数则停止游戏, 反之则传递中奖索引\n if (index < 0) {\n this.step = 0\n this.prizeFlag = -1\n } else {\n this.step = 2\n this.prizeFlag = index % this.prizes.length\n }\n }\n\n /**\n * 实际开始执行方法\n * @param num 记录帧动画执行多少次\n */\n private run (num: number = 0): void {\n const { rAF, step, prizeFlag, _defaultConfig } = this\n const { accelerationTime, decelerationTime, speed } = _defaultConfig\n // 游戏结束\n if (step === 0) {\n this.endCallback?.(this.prizes.find((prize, index) => index === prizeFlag) || {})\n return\n }\n // 如果等于 -1 就直接停止游戏\n if (prizeFlag === -1) return\n // 计算结束位置\n if (step === 3 && !this.endDeg) this.carveOnGunwaleOfAMovingBoat()\n // 计算时间间隔\n const startInterval = Date.now() - this.startTime\n const endInterval = Date.now() - this.endTime\n let rotateDeg = this.rotateDeg\n // \n if (step === 1 || startInterval < accelerationTime) { // 加速阶段\n // 记录帧率\n this.FPS = startInterval / num\n const currSpeed = quad.easeIn(startInterval, 0, speed, accelerationTime)\n // 加速到峰值后, 进入匀速阶段\n if (currSpeed === speed) {\n this.step = 2\n }\n rotateDeg = rotateDeg + currSpeed % 360\n } else if (step === 2) { // 匀速阶段\n // 速度保持不变\n rotateDeg = rotateDeg + speed % 360\n // 如果 prizeFlag 有值, 则进入减速阶段\n if (prizeFlag !== void 0 && prizeFlag >= 0) {\n this.step = 3\n // 清空上一次的位置信息\n this.stopDeg = 0\n this.endDeg = 0\n }\n } else if (step === 3) { // 减速阶段\n // 开始缓慢停止\n rotateDeg = quad.easeOut(endInterval, this.stopDeg, this.endDeg, decelerationTime)\n if (endInterval >= decelerationTime) {\n this.step = 0\n }\n } else {\n // 出现异常\n this.stop(-1)\n }\n this.rotateDeg = rotateDeg\n this.draw()\n rAF(this.run.bind(this, num + 1))\n }\n\n /**\n * 换算渲染坐标\n * @param x\n * @param y\n */\n protected conversionAxis (x: number, y: number): [number, number] {\n const { config } = this\n return [x / config.dpr - this.Radius, y / config.dpr - this.Radius]\n }\n}\n","import Lucky from './lucky'\nimport { UserConfigType, ImgType } from '../types/index'\nimport LuckyGridConfig, {\n BlockType,\n PrizeType,\n ButtonType,\n CellFontType,\n CellImgType,\n RowsType,\n ColsType,\n CellType,\n DefaultConfigType,\n DefaultStyleType,\n ActiveStyleType,\n StartCallbackType,\n EndCallbackType,\n} from '../types/grid'\nimport {\n has,\n isExpectType,\n removeEnter,\n computePadding,\n hasBackground,\n computeRange,\n splitText\n} from '../utils/index'\nimport { roundRectByArc, getLinearGradient } from '../utils/math'\nimport { quad } from '../utils/tween'\n\nexport default class LuckyGrid extends Lucky {\n private rows: RowsType = 3\n private cols: ColsType = 3\n private blocks: Array<BlockType> = []\n private prizes: Array<PrizeType> = []\n private buttons: Array<ButtonType> = []\n private button?: ButtonType\n private defaultConfig: DefaultConfigType = {}\n private defaultStyle: DefaultStyleType = {}\n private activeStyle: ActiveStyleType = {}\n private _defaultConfig: Required<DefaultConfigType> = {} as Required<DefaultConfigType>\n private _defaultStyle: Required<DefaultStyleType> = {} as Required<DefaultStyleType>\n private _activeStyle: Required<ActiveStyleType> = {} as Required<ActiveStyleType>\n private startCallback?: StartCallbackType\n private endCallback?: EndCallbackType\n private cellWidth = 0 // 格子宽度\n private cellHeight = 0 // 格子高度\n private startTime = 0 // 开始时间戳\n private endTime = 0 // 结束时间戳\n private currIndex = 0 // 当前index累加\n private stopIndex = 0 // 刻舟求剑\n private endIndex = 0 // 停止索引\n private demo = false // 是否自动游走\n private timer = 0 // 游走定时器\n private FPS = 16.6 // 屏幕刷新率\n /**\n * 游戏当前的阶段\n * step = 0 时, 游戏尚未开始\n * step = 1 时, 此时处于加速阶段\n * step = 2 时, 此时处于匀速阶段\n * step = 3 时, 此时处于减速阶段\n */\n private step: 0 | 1 | 2 | 3 = 0\n /**\n * 中奖索引\n * prizeFlag = undefined 时, 处于开始抽奖阶段, 正常旋转\n * prizeFlag >= 0 时, 说明stop方法被调用, 并且传入了中奖索引\n * prizeFlag === -1 时, 说明stop方法被调用, 并且传入了负值, 本次抽奖无效\n */\n private prizeFlag: number | undefined = -1\n // 所有格子\n private cells: CellType<CellFontType, CellImgType>[] = []\n // 奖品区域几何信息\n private prizeArea: { x: number, y: number, w: number, h: number } | undefined\n // 图片缓存\n private ImageCache = new Map()\n\n /**\n * 九宫格构造器\n * @param config 配置项\n * @param data 抽奖数据\n */\n constructor (config: UserConfigType, data: LuckyGridConfig) {\n super(config, {\n width: data.width,\n height: data.height\n })\n this.initData(data)\n this.initWatch()\n this.initComputed()\n // 创建前回调函数\n config.beforeCreate?.call(this)\n // 首次初始化\n this.init()\n }\n\n protected resize(): void {\n super.resize()\n this.draw()\n this.config.afterResize?.()\n }\n\n protected initLucky (): void {\n this.cellWidth = 0\n this.cellHeight = 0\n this.startTime = 0\n this.endTime = 0\n this.currIndex = 0\n this.stopIndex = 0\n this.endIndex = 0\n this.demo = false\n this.timer = 0\n this.FPS = 16.6\n this.prizeFlag = -1\n this.step = 0\n super.initLucky()\n }\n\n /**\n * 初始化数据\n * @param data\n */\n private initData (data: LuckyGridConfig): void {\n this.$set(this, 'width', data.width)\n this.$set(this, 'height', data.height)\n this.$set(this, 'rows', Number(data.rows) || 3)\n this.$set(this, 'cols', Number(data.cols) || 3)\n this.$set(this, 'blocks', data.blocks || [])\n this.$set(this, 'prizes', data.prizes || [])\n this.$set(this, 'buttons', data.buttons || [])\n // 临时过渡代码, 升级到2.x即可删除\n this.$set(this, 'button', data.button)\n this.$set(this, 'defaultConfig', data.defaultConfig || {})\n this.$set(this, 'defaultStyle', data.defaultStyle || {})\n this.$set(this, 'activeStyle', data.activeStyle || {})\n this.$set(this, 'startCallback', data.start)\n this.$set(this, 'endCallback', data.end)\n }\n\n /**\n * 初始化属性计算\n */\n private initComputed (): void {\n // 默认配置\n this.$computed(this, '_defaultConfig', () => {\n const config = {\n gutter: 5,\n speed: 20,\n accelerationTime: 2500,\n decelerationTime: 2500,\n ...this.defaultConfig\n }\n config.gutter = this.getLength(config.gutter)\n config.speed = config.speed / 40\n return config\n })\n // 默认样式\n this.$computed(this, '_defaultStyle', () => {\n return {\n borderRadius: 20,\n fontColor: '#000',\n fontSize: '18px',\n fontStyle: 'sans-serif',\n fontWeight: '400',\n background: 'rgba(0,0,0,0)',\n shadow: '',\n wordWrap: true,\n lengthLimit: '90%',\n ...this.defaultStyle\n }\n })\n // 中奖样式\n this.$computed(this, '_activeStyle', () => {\n return {\n background: '#ffce98',\n shadow: '',\n ...this.activeStyle\n }\n })\n }\n\n /**\n * 初始化观察者\n */\n private initWatch (): void {\n // 重置宽度\n this.$watch('width', (newVal: string | number) => {\n this.data.width = newVal\n this.resize()\n })\n // 重置高度\n this.$watch('height', (newVal: string | number) => {\n this.data.height = newVal\n this.resize()\n })\n // 监听 blocks 数据的变化\n this.$watch('blocks', (newData: Array<BlockType>) => {\n this.initImageCache()\n }, { deep: true })\n // 监听 prizes 数据的变化\n this.$watch('prizes', (newData: Array<PrizeType>) => {\n this.initImageCache()\n }, { deep: true })\n // 监听 button 数据的变化\n this.$watch('buttons', (newData: Array<ButtonType>) => {\n this.initImageCache()\n }, { deep: true })\n this.$watch('rows', () => this.init())\n this.$watch('cols', () => this.init())\n this.$watch('defaultConfig', () => this.draw(), { deep: true })\n this.$watch('defaultStyle', () => this.draw(), { deep: true })\n this.$watch('activeStyle', () => this.draw(), { deep: true })\n this.$watch('startCallback', () => this.init())\n this.$watch('endCallback', () => this.init())\n }\n\n /**\n * 初始化 canvas 抽奖\n */\n public async init (): Promise<void> {\n this.initLucky()\n const { config } = this\n // 初始化前回调函数\n config.beforeInit?.call(this)\n // 先画一次防止闪烁\n this.draw()\n // 异步加载图片\n await this.initImageCache()\n // 初始化后回调函数\n config.afterInit?.call(this)\n }\n\n private initImageCache (): Promise<void> {\n return new Promise((resolve) => {\n const btnImgs = this.buttons.map(btn => btn.imgs)\n if (this.button) btnImgs.push(this.button.imgs)\n const willUpdateImgs = {\n blocks: this.blocks.map(block => block.imgs),\n prizes: this.prizes.map(prize => prize.imgs),\n buttons: btnImgs,\n }\n ;(<(keyof typeof willUpdateImgs)[]>Object.keys(willUpdateImgs)).forEach(imgName => {\n const willUpdate = willUpdateImgs[imgName]\n // 循环遍历所有图片\n const allPromise: Promise<void>[] = []\n willUpdate && willUpdate.forEach((imgs, cellIndex) => {\n imgs && imgs.forEach((imgInfo, imgIndex) => {\n allPromise.push(this.loadAndCacheImg(imgName, cellIndex, imgIndex))\n })\n })\n Promise.all(allPromise).then(() => {\n this.draw()\n resolve()\n })\n })\n })\n }\n\n /**\n * canvas点击事件\n * @param e 事件参数\n */\n protected handleClick (e: MouseEvent): void {\n const { ctx } = this\n ;[\n ...this.buttons,\n this.button\n ].forEach(btn => {\n if (!btn) return\n const [x, y, width, height] = this.getGeometricProperty([\n btn.x, btn.y, btn.col || 1, btn.row || 1\n ])\n ctx.beginPath()\n ctx.rect(x, y, width, height)\n if (!ctx.isPointInPath(e.offsetX, e.offsetY)) return\n if (this.step !== 0) return\n // 如果btn里有单独的回调方法, 优先触发\n if (typeof btn.callback === 'function') btn.callback.call(this, btn)\n // 最后触发公共回调\n this.startCallback?.(e, btn)\n })\n }\n\n /**\n * 根据索引单独加载指定图片并缓存\n * @param cellName 模块名称\n * @param cellIndex 模块索引\n * @param imgName 模块对应的图片缓存\n * @param imgIndex 图片索引\n */\n private async loadAndCacheImg (\n cellName: 'blocks' | 'prizes' | 'buttons',\n cellIndex: number,\n imgIndex: number\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n let cell: BlockType | PrizeType | ButtonType = this[cellName][cellIndex]\n // 临时过渡代码, 升级到2.x即可删除\n if (cellName === 'buttons' && !this.buttons.length && this.button) {\n cell = this.button\n }\n if (!cell || !cell.imgs) return\n const imgInfo = cell.imgs[imgIndex]\n if (!imgInfo) return\n // 异步加载图片\n const request = [\n this.loadImg(imgInfo.src, imgInfo),\n imgInfo['activeSrc'] && this.loadImg(imgInfo['activeSrc'], imgInfo, '$activeResolve')\n ]\n Promise.all(request).then(async ([defaultImg, activeImg]) => {\n const formatter = imgInfo.formatter\n // 对图片进行处理\n if (typeof formatter === 'function') {\n defaultImg = await Promise.resolve(formatter.call(this, defaultImg))\n if (activeImg) {\n activeImg = await Promise.resolve(formatter.call(this, activeImg))\n }\n }\n this.ImageCache.set(imgInfo['src'], defaultImg)\n activeImg && this.ImageCache.set(imgInfo['activeSrc'], activeImg)\n resolve()\n }).catch(err => {\n console.error(`${cellName}[${cellIndex}].imgs[${imgIndex}] ${err}`)\n reject()\n })\n })\n }\n\n /**\n * 绘制九宫格抽奖\n */\n protected draw (): void {\n const { config, ctx, _defaultConfig, _defaultStyle, _activeStyle } = this\n // 触发绘制前回调\n config.beforeDraw?.call(this, ctx)\n // 清空画布\n ctx.clearRect(0, 0, this.boxWidth, this.boxHeight)\n // 合并奖品和按钮\n this.cells = [\n ...this.prizes,\n ...this.buttons\n ]\n if (this.button) this.cells.push(this.button)\n this.cells.forEach(cell => {\n cell.col = cell.col || 1\n cell.row = cell.row || 1\n })\n // 计算获取奖品区域的几何信息\n this.prizeArea = this.blocks.reduce(({x, y, w, h}, block, blockIndex) => {\n const [paddingTop, paddingBottom, paddingLeft, paddingRight] = computePadding(block, this.getLength.bind(this))\n const r = block.borderRadius ? this.getLength(block.borderRadius) : 0\n // 绘制边框\n const background = block.background\n if (hasBackground(background)) {\n ctx.fillStyle = this.handleBackground(x, y, w, h, background!)\n roundRectByArc(ctx, x, y, w, h, r)\n ctx.fill()\n }\n // 绘制图片\n block.imgs && block.imgs.forEach((imgInfo, imgIndex) => {\n const blockImg = this.ImageCache.get(imgInfo.src)\n if (!blockImg) return\n // 绘制图片\n const [trueWidth, trueHeight] = this.computedWidthAndHeight(blockImg, imgInfo, w, h)\n const [xAxis, yAxis] = [\n this.getOffsetX(trueWidth, w) + this.getLength(imgInfo.left, w),\n this.getLength(imgInfo.top, h)\n ]\n this.drawImage(ctx, blockImg, x + xAxis, y + yAxis, trueWidth, trueHeight)\n })\n return {\n x: x + paddingLeft,\n y: y + paddingTop,\n w: w - paddingLeft - paddingRight,\n h: h - paddingTop - paddingBottom\n }\n }, { x: 0, y: 0, w: this.boxWidth, h: this.boxHeight })\n // 计算单一奖品格子的宽度和高度\n this.cellWidth = (this.prizeArea.w - _defaultConfig.gutter * (this.cols - 1)) / this.cols\n this.cellHeight = (this.prizeArea.h - _defaultConfig.gutter * (this.rows - 1)) / this.rows\n // 绘制所有格子\n this.cells.forEach((cell, cellIndex) => {\n let [x, y, width, height] = this.getGeometricProperty([cell.x, cell.y, cell.col!, cell.row!])\n // 默认不显示中奖标识\n let isActive = false\n // 只要 prizeFlag 不是负数, 就显示中奖标识\n if (this.prizeFlag === void 0 || this.prizeFlag > -1) {\n isActive = cellIndex === this.currIndex % this.prizes.length >> 0\n }\n // 绘制背景色\n const background = isActive ? _activeStyle.background : (cell.background || _defaultStyle.background)\n if (hasBackground(background)) {\n // 处理阴影 (暂时先用any, 这里后续要优化)\n const shadow: any = (\n isActive ? _activeStyle.shadow : (cell.shadow || _defaultStyle.shadow)\n )\n .replace(/px/g, '') // 清空px字符串\n .split(',')[0].split(' ') // 防止有人声明多个阴影, 截取第一个阴影\n .map((n, i) => i < 3 ? Number(n) : n) // 把数组的前三个值*像素比\n // 绘制阴影\n if (shadow.length === 4) {\n ctx.shadowColor = shadow[3]\n ctx.shadowOffsetX = shadow[0] * config.dpr\n ctx.shadowOffsetY = shadow[1] * config.dpr\n ctx.shadowBlur = shadow[2]\n // 修正(格子+阴影)的位置, 这里使用逗号运算符\n shadow[0] > 0 ? (width -= shadow[0]) : (width += shadow[0], x -= shadow[0])\n shadow[1] > 0 ? (height -= shadow[1]) : (height += shadow[1], y -= shadow[1])\n }\n // 绘制背景\n ctx.fillStyle = this.handleBackground(x, y, width, height, background)\n const borderRadius = this.getLength(cell.borderRadius ? cell.borderRadius : _defaultStyle.borderRadius)\n roundRectByArc(ctx, x, y, width, height, borderRadius)\n ctx.fill()\n // 清空阴影\n ctx.shadowColor = 'rgba(0, 0, 0, 0)'\n ctx.shadowOffsetX = 0\n ctx.shadowOffsetY = 0\n ctx.shadowBlur = 0\n }\n // 修正图片缓存\n let cellName = 'prizes'\n if (cellIndex >= this.prizes.length) {\n cellName = 'buttons'\n cellIndex -= this.prizes.length\n }\n // 绘制图片\n cell.imgs && cell.imgs.forEach((imgInfo, imgIndex) => {\n const cellImg = this.ImageCache.get(imgInfo.src)\n const activeImg = this.ImageCache.get(imgInfo['activeSrc'])\n if (!cellImg) return\n const renderImg = (isActive && activeImg) || cellImg\n if (!renderImg) return\n const [trueWidth, trueHeight] = this.computedWidthAndHeight(renderImg, imgInfo, width, height)\n const [xAxis, yAxis] = [\n x + this.getOffsetX(trueWidth, width) + this.getLength(imgInfo.left, width),\n y + this.getLength(imgInfo.top, height)\n ]\n this.drawImage(ctx, renderImg, xAxis, yAxis, trueWidth, trueHeight)\n })\n // 绘制文字\n cell.fonts && cell.fonts.forEach(font => {\n // 字体样式\n const style = isActive && _activeStyle.fontStyle\n ? _activeStyle.fontStyle\n : (font.fontStyle || _defaultStyle.fontStyle)\n // 字体加粗\n const fontWeight = isActive && _activeStyle.fontWeight\n ? _activeStyle.fontWeight\n : (font.fontWeight || _defaultStyle.fontWeight)\n // 字体大小\n const size = isActive && _activeStyle.fontSize\n ? this.getLength(_activeStyle.fontSize)\n : this.getLength(font.fontSize || _defaultStyle.fontSize)\n // 字体行高\n const lineHeight = isActive && _activeStyle.lineHeight\n ? _activeStyle.lineHeight\n : font.lineHeight || _defaultStyle.lineHeight || font.fontSize || _defaultStyle.fontSize\n const wordWrap = has(font, 'wordWrap') ? font.wordWrap : _defaultStyle.wordWrap\n const lengthLimit = font.lengthLimit || _defaultStyle.lengthLimit\n const lineClamp = font.lineClamp || _defaultStyle.lineClamp\n ctx.font = `${fontWeight} ${size >> 0}px ${style}`\n ctx.fillStyle = (isActive && _activeStyle.fontColor) ? _activeStyle.fontColor : (font.fontColor || _defaultStyle.fontColor)\n let lines = [], text = String(font.text)\n // 计算文字换行\n if (wordWrap) {\n // 最大宽度\n let maxWidth = this.getLength(lengthLimit, width)\n lines = splitText(ctx, removeEnter(text), () => maxWidth, lineClamp)\n } else {\n lines = text.split('\\n')\n }\n lines.forEach((line, lineIndex) => {\n ctx.fillText(\n line,\n x + this.getOffsetX(ctx.measureText(line).width, width) + this.getLength(font.left, width),\n y + this.getLength(font.top, height) + (lineIndex + 1) * this.getLength(lineHeight)\n )\n })\n })\n })\n // 触发绘制后回调\n config.afterDraw?.call(this, ctx)\n }\n\n /**\n * 处理背景色\n * @param x\n * @param y\n * @param width\n * @param height\n * @param background\n * @param isActive\n */\n private handleBackground (\n x: number,\n y: number,\n width: number,\n height: number,\n background: string,\n ) {\n const { ctx } = this\n // 处理线性渐变\n if (background.includes('linear-gradient')) {\n background = getLinearGradient(ctx, x, y, width, height, background)\n }\n return background\n }\n\n /**\n * 刻舟求剑\n */\n private carveOnGunwaleOfAMovingBoat (): void {\n const { _defaultConfig, prizeFlag, currIndex } = this\n this.endTime = Date.now()\n const stopIndex = this.stopIndex = currIndex\n const speed = _defaultConfig.speed\n let i = 0, prevSpeed = 0, prevIndex = 0\n while (++i) {\n const endIndex = this.prizes.length * i + prizeFlag! - (stopIndex)\n const currSpeed = quad.easeOut(this.FPS, stopIndex, endIndex, _defaultConfig.decelerationTime) - stopIndex\n if (currSpeed > speed) {\n this.endIndex = (speed - prevSpeed > currSpeed - speed) ? endIndex : prevIndex\n break\n }\n prevIndex = endIndex\n prevSpeed = currSpeed\n }\n }\n\n /**\n * 对外暴露: 开始抽奖方法\n */\n public play (): void {\n if (this.step !== 0) return\n // 记录游戏开始的时间\n this.startTime = Date.now()\n // 重置中奖索引\n this.prizeFlag = void 0\n // 开始加速\n this.step = 1\n // 触发回调\n this.config.afterStart?.()\n // 开始运行\n this.run()\n }\n\n /**\n * 对外暴露: 缓慢停止方法\n * @param index 中奖索引\n */\n public stop (index?: number): void {\n if (this.step === 0 || this.step === 3) return\n // 如果没有传递中奖索引, 则通过range属性计算一个\n if (!index && index !== 0) {\n const rangeArr = this.prizes.map(item => item.range)\n index = computeRange(rangeArr)\n }\n // 如果index是负数则停止游戏, 反之则传递中奖索引\n if (index < 0) {\n this.step = 0\n this.prizeFlag = -1\n } else {\n this.step = 2\n this.prizeFlag = index % this.prizes.length\n }\n }\n\n /**\n * 实际开始执行方法\n * @param num 记录帧动画执行多少次\n */\n private run (num: number = 0): void {\n const { rAF, step, prizes, prizeFlag, _defaultConfig } = this\n const { accelerationTime, decelerationTime, speed } = _defaultConfig\n // 结束游戏\n if (step === 0) {\n this.endCallback?.(this.prizes.find((prize, index) => index === prizeFlag) || {})\n return\n }\n // 如果等于 -1 就直接停止游戏\n if (prizeFlag === -1) return\n // 计算结束位置\n if (step === 3 && !this.endIndex) this.carveOnGunwaleOfAMovingBoat()\n // 计算时间间隔\n const startInterval = Date.now() - this.startTime\n const endInterval = Date.now() - this.endTime\n let currIndex = this.currIndex\n // \n if (step === 1 || startInterval < accelerationTime) { // 加速阶段\n // 记录帧率\n this.FPS = startInterval / num\n const currSpeed = quad.easeIn(startInterval, 0.1, speed - 0.1, accelerationTime)\n // 加速到峰值后, 进入匀速阶段\n if (currSpeed === speed) {\n this.step = 2\n }\n currIndex = currIndex + currSpeed % prizes.length\n } else if (step === 2) { // 匀速阶段\n // 速度保持不变\n currIndex = currIndex + speed % prizes.length\n // 如果 prizeFlag 有值, 则进入减速阶段\n if (prizeFlag !== void 0 && prizeFlag >= 0) {\n this.step = 3\n // 清空上一次的位置信息\n this.stopIndex = 0\n this.endIndex = 0\n }\n } else if (step === 3) { // 减速阶段\n // 开始缓慢停止\n currIndex = quad.easeOut(endInterval, this.stopIndex, this.endIndex, decelerationTime)\n if (endInterval >= decelerationTime) {\n this.step = 0\n }\n } else {\n // 出现异常\n this.stop(-1)\n }\n this.currIndex = currIndex\n this.draw()\n rAF(this.run.bind(this, num + 1))\n }\n\n /**\n * 计算奖品格子的几何属性\n * @param { array } [...矩阵坐标, col, row]\n * @return { array } [...真实坐标, width, height]\n */\n private getGeometricProperty ([x, y, col = 1, row = 1]: number[]) {\n const { cellWidth, cellHeight } = this\n const gutter = this._defaultConfig.gutter\n let res = [\n this.prizeArea!.x + (cellWidth + gutter) * x,\n this.prizeArea!.y + (cellHeight + gutter) * y\n ]\n col && row && res.push(\n cellWidth * col + gutter * (col - 1),\n cellHeight * row + gutter * (row - 1),\n )\n return res\n }\n\n /**\n * 换算渲染坐标\n * @param x\n * @param y\n */\n protected conversionAxis (x: number, y: number): [number, number] {\n const { config } = this\n return [x / config.dpr, y / config.dpr]\n }\n}\n","import Lucky from './lucky'\nimport { UserConfigType, ImgType, ImgItemType, Tuple } from '../types/index'\nimport SlotMachineConfig, {\n BlockType,\n PrizeType,\n SlotType,\n DefaultConfigType,\n DefaultStyleType,\n EndCallbackType,\n} from '../types/slot'\nimport {\n get, has,\n isExpectType,\n removeEnter,\n computePadding,\n hasBackground,\n computeRange,\n splitText,\n getSortedArrayByIndex\n} from '../utils/index'\nimport { roundRectByArc } from '../utils/math'\nimport { quad } from '../utils/tween'\n\nexport default class SlotMachine extends Lucky {\n // 背景\n private blocks: Array<BlockType> = []\n // 奖品列表\n private prizes: Array<PrizeType> = []\n // 插槽列表\n private slots: Array<SlotType> = []\n // 默认配置\n private defaultConfig: DefaultConfigType = {}\n private _defaultConfig: Required<DefaultConfigType> = {} as Required<DefaultConfigType>\n // 默认样式\n private defaultStyle: DefaultStyleType = {}\n private _defaultStyle: Required<DefaultStyleType> = {} as Required<DefaultStyleType>\n private endCallback: EndCallbackType = () => {}\n // 离屏canvas\n private _offscreenCanvas?: HTMLCanvasElement\n private cellWidth = 0 // 格子宽度\n private cellHeight = 0 // 格子高度\n private cellAndSpacing = 0 // 格子+间距\n private widthAndSpacing = 0 // 格子宽度+列间距\n private heightAndSpacing = 0 // 格子高度+行间距\n private FPS = 16.6 // 屏幕刷新率\n private scroll: number[] = [] // 滚动的长度\n private stopScroll: number[] = [] // 刻舟求剑\n private endScroll: number[] = [] // 最终停止的长度\n private startTime = 0 // 开始游戏的时间\n private endTime = 0 // 开始停止的时间\n /**\n * 游戏当前的阶段\n * step = 0 时, 游戏尚未开始\n * step = 1 时, 此时处于加速阶段\n * step = 2 时, 此时处于匀速阶段\n * step = 3 时, 此时处于减速阶段\n */\n private step: 0 | 1 | 2 | 3 = 0\n /**\n * 中奖索引\n * prizeFlag = undefined 时, 处于开始抽奖阶段, 正常旋转\n * prizeFlag >= 0 时, 说明stop方法被调用, 并且传入了中奖索引\n * prizeFlag === -1 时, 说明stop方法被调用, 并且传入了负值, 本次抽奖无效\n */\n private prizeFlag: number[] | undefined = void 0\n // 奖品区域几何信息\n private prizeArea?: { x: number, y: number, w: number, h: number }\n // 图片缓存\n private ImageCache = new Map()\n\n /**\n * 老虎机构造器\n * @param config 配置项\n * @param data 抽奖数据\n */\n constructor (config: UserConfigType, data: SlotMachineConfig) {\n super(config, {\n width: data.width,\n height: data.height\n })\n this.initData(data)\n this.initWatch()\n this.initComputed()\n // 创建前回调函数\n config.beforeCreate?.call(this)\n // 首次初始化\n this.init()\n }\n\n protected resize(): void {\n super.resize()\n this.draw()\n this.config.afterResize?.()\n }\n\n protected initLucky (): void {\n this.cellWidth = 0\n this.cellHeight = 0\n this.cellAndSpacing = 0\n this.widthAndSpacing = 0\n this.heightAndSpacing = 0\n this.FPS = 16.6\n this.scroll = []\n this.stopScroll = []\n this.endScroll = []\n this.startTime = 0\n this.endTime = 0\n this.prizeFlag = void 0\n this.step = 0\n super.initLucky()\n }\n\n /**\n * 初始化数据\n * @param data\n */\n private initData (data: SlotMachineConfig): void {\n this.$set(this, 'width', data.width)\n this.$set(this, 'height', data.height)\n this.$set(this, 'blocks', data.blocks || [])\n this.$set(this, 'prizes', data.prizes || [])\n this.$set(this, 'slots', data.slots || [])\n this.$set(this, 'defaultConfig', data.defaultConfig || {})\n this.$set(this, 'defaultStyle', data.defaultStyle || {})\n this.$set(this, 'endCallback', data.end)\n }\n\n /**\n * 初始化属性计算\n */\n private initComputed (): void {\n // 默认配置\n this.$computed(this, '_defaultConfig', () => {\n const config = {\n mode: 'vertical',\n rowSpacing: 0,\n colSpacing: 5,\n speed: 20,\n direction: 1,\n accelerationTime: 2500,\n decelerationTime: 2500,\n ...this.defaultConfig\n }\n config.rowSpacing = this.getLength(config.rowSpacing)\n config.colSpacing = this.getLength(config.colSpacing)\n return config\n })\n // 默认样式\n this.$computed(this, '_defaultStyle', () => {\n return {\n borderRadius: 0,\n fontColor: '#000',\n fontSize: '18px',\n fontStyle: 'sans-serif',\n fontWeight: '400',\n background: 'rgba(0,0,0,0)',\n wordWrap: true,\n lengthLimit: '90%',\n ...this.defaultStyle\n }\n })\n }\n\n /**\n * 初始化观察者\n */\n private initWatch (): void {\n // 重置宽度\n this.$watch('width', (newVal: string | number) => {\n this.data.width = newVal\n this.resize()\n })\n // 重置高度\n this.$watch('height', (newVal: string | number) => {\n this.data.height = newVal\n this.resize()\n })\n // 监听 blocks 数据的变化\n this.$watch('blocks', (newData: Array<BlockType>) => {\n this.initImageCache()\n }, { deep: true })\n // 监听 prizes 数据的变化\n this.$watch('prizes', (newData: Array<PrizeType>) => {\n this.initImageCache()\n }, { deep: true })\n // 监听 prizes 数据的变化\n this.$watch('slots', (newData: Array<PrizeType>) => {\n this.drawOffscreenCanvas()\n this.draw()\n }, { deep: true })\n this.$watch('defaultConfig', () => this.draw(), { deep: true })\n this.$watch('defaultStyle', () => this.draw(), { deep: true })\n this.$watch('endCallback', () => this.init())\n }\n\n /**\n * 初始化 canvas 抽奖\n */\n public async init (): Promise<void> {\n this.initLucky()\n const { config } = this\n // 初始化前回调函数\n config.beforeInit?.call(this)\n // 先绘制一次\n this.drawOffscreenCanvas()\n this.draw()\n // 异步加载图片\n await this.initImageCache()\n // 初始化后回调函数\n config.afterInit?.call(this)\n }\n\n private initImageCache (): Promise<void> {\n return new Promise((resolve) => {\n const willUpdateImgs = {\n blocks: this.blocks.map(block => block.imgs),\n prizes: this.prizes.map(prize => prize.imgs),\n }\n ;(<(keyof typeof willUpdateImgs)[]>Object.keys(willUpdateImgs)).forEach(imgName => {\n const willUpdate = willUpdateImgs[imgName]\n // 循环遍历所有图片\n const allPromise: Promise<void>[] = []\n willUpdate && willUpdate.forEach((imgs, cellIndex) => {\n imgs && imgs.forEach((imgInfo, imgIndex) => {\n allPromise.push(this.loadAndCacheImg(imgName, cellIndex, imgIndex))\n })\n })\n Promise.all(allPromise).then(() => {\n this.drawOffscreenCanvas()\n this.draw()\n resolve()\n })\n })\n })\n }\n\n /**\n * 根据索引单独加载指定图片并缓存\n * @param cellName 模块名称\n * @param cellIndex 模块索引\n * @param imgName 模块对应的图片缓存\n * @param imgIndex 图片索引\n */\n private async loadAndCacheImg (\n cellName: 'blocks' | 'prizes',\n cellIndex: number,\n imgIndex: number\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n let cell: BlockType | PrizeType = this[cellName][cellIndex]\n if (!cell || !cell.imgs) return\n const imgInfo = cell.imgs[imgIndex]\n if (!imgInfo) return\n // 异步加载图片\n this.loadImg(imgInfo.src, imgInfo).then(async currImg => {\n if (typeof imgInfo.formatter === 'function') {\n currImg = await Promise.resolve(imgInfo.formatter.call(this, currImg))\n }\n this.ImageCache.set(imgInfo['src'], currImg)\n resolve()\n }).catch(err => {\n console.error(`${cellName}[${cellIndex}].imgs[${imgIndex}] ${err}`)\n reject()\n })\n })\n }\n\n /**\n * 绘制离屏canvas\n */\n protected drawOffscreenCanvas (): void {\n const { _defaultConfig, _defaultStyle } = this\n const { w, h } = this.drawBlocks()!\n // 计算单一奖品格子的宽度和高度\n const prizesLen = this.prizes.length\n const { cellWidth, cellHeight, widthAndSpacing, heightAndSpacing } = this.displacementWidthOrHeight()\n const defaultOrder = new Array(prizesLen).fill(void 0).map((v, i) => i)\n let maxOrderLen = 0, maxOffWidth = 0, maxOffHeight = 0\n this.slots.forEach((slot, slotIndex) => {\n // 初始化 scroll 的值\n if (this.scroll[slotIndex] === void 0) this.scroll[slotIndex] = 0\n // 如果没有order属性, 就填充prizes\n slot.order = slot.order || defaultOrder\n // 计算最大值\n const currLen = slot.order.length\n maxOrderLen = Math.max(maxOrderLen, currLen)\n maxOffWidth = Math.max(maxOffWidth, w + widthAndSpacing * currLen)\n maxOffHeight = Math.max(maxOffHeight, h + heightAndSpacing * currLen)\n })\n // 创建一个离屏Canvas来存储画布的内容\n const { _offscreenCanvas, _ctx } = this.getOffscreenCanvas(maxOffWidth, maxOffHeight)!\n this._offscreenCanvas = _offscreenCanvas\n // 绘制插槽\n this.slots.forEach((slot, slotIndex) => {\n const cellX = cellWidth * slotIndex\n const cellY = cellHeight * slotIndex\n let lengthOfCopy = 0\n // 绘制奖品\n const newPrizes = getSortedArrayByIndex(this.prizes, slot.order!)\n // 如果没有奖品则打断逻辑\n if (!newPrizes.length) return\n newPrizes.forEach((cell, cellIndex) => {\n if (!cell) return\n const orderIndex = slot.order![cellIndex]\n const prizesX = widthAndSpacing * cellIndex + _defaultConfig.colSpacing / 2\n const prizesY = heightAndSpacing * cellIndex + _defaultConfig.rowSpacing / 2\n const [_x, _y, spacing] = this.displacement(\n [cellX, prizesY, heightAndSpacing],\n [prizesX, cellY, widthAndSpacing]\n )\n lengthOfCopy += spacing\n // 绘制背景\n const background = cell.background || _defaultStyle.background\n if (hasBackground(background)) {\n const borderRadius = this.getLength(has(cell, 'borderRadius') ? cell.borderRadius : _defaultStyle.borderRadius)\n roundRectByArc(_ctx, _x, _y, cellWidth, cellWidth, borderRadius)\n _ctx.fillStyle = background\n _ctx.fill()\n }\n // 绘制图片\n cell.imgs && cell.imgs.forEach((imgInfo, imgIndex) => {\n const cellImg = this.ImageCache.get(imgInfo.src)\n if (!cellImg) return\n const [trueWidth, trueHeight] = this.computedWidthAndHeight(cellImg, imgInfo, cellWidth, cellHeight)\n const [xAxis, yAxis] = [\n _x + this.getOffsetX(trueWidth, cellWidth) + this.getLength(imgInfo.left, cellWidth),\n _y + this.getLength(imgInfo.top, cellHeight)\n ]\n this.drawImage(_ctx, cellImg, xAxis, yAxis, trueWidth, trueHeight)\n })\n // 绘制文字\n cell.fonts && cell.fonts.forEach(font => {\n // 字体样式\n const style = font.fontStyle || _defaultStyle.fontStyle\n // 字体加粗\n const fontWeight = font.fontWeight || _defaultStyle.fontWeight\n // 字体大小\n const size = this.getLength(font.fontSize || _defaultStyle.fontSize)\n // 字体行高\n const lineHeight = font.lineHeight || _defaultStyle.lineHeight || font.fontSize || _defaultStyle.fontSize\n const wordWrap = has(font, 'wordWrap') ? font.wordWrap : _defaultStyle.wordWrap\n const lengthLimit = font.lengthLimit || _defaultStyle.lengthLimit\n const lineClamp = font.lineClamp || _defaultStyle.lineClamp\n _ctx.font = `${fontWeight} ${size >> 0}px ${style}`\n _ctx.fillStyle = font.fontColor || _defaultStyle.fontColor\n let lines = [], text = String(font.text)\n // 计算文字换行\n if (wordWrap) {\n // 最大宽度\n let maxWidth = this.getLength(lengthLimit, cellWidth)\n lines = splitText(_ctx, removeEnter(text), () => maxWidth, lineClamp)\n } else {\n lines = text.split('\\n')\n }\n lines.forEach((line, lineIndex) => {\n _ctx.fillText(\n line,\n _x + this.getOffsetX(_ctx.measureText(line).width, cellWidth) + this.getLength(font.left, cellWidth),\n _y + this.getLength(font.top, cellHeight) + (lineIndex + 1) * this.getLength(lineHeight)\n )\n })\n })\n })\n const [_x, _y, _w, _h] = this.displacement(\n [cellX, 0, cellWidth, lengthOfCopy],\n [0, cellY, lengthOfCopy, cellHeight]\n )\n let drawLen = lengthOfCopy\n while (drawLen < maxOffHeight + lengthOfCopy) {\n const [drawX, drawY] = this.displacement([_x, drawLen], [drawLen, _y])\n this.drawImage(\n _ctx, _offscreenCanvas,\n _x, _y, _w, _h,\n drawX, drawY, _w, _h\n )\n drawLen += lengthOfCopy\n }\n })\n }\n\n /**\n * 绘制背景区域\n */\n protected drawBlocks (): SlotMachine['prizeArea'] {\n const { config, ctx, _defaultConfig, _defaultStyle } = this\n // 绘制背景区域, 并计算奖品区域\n return this.prizeArea = this.blocks.reduce(({x, y, w, h}, block, blockIndex) => {\n const [paddingTop, paddingBottom, paddingLeft, paddingRight] = computePadding(block, this.getLength.bind(this))\n const r = block.borderRadius ? this.getLength(block.borderRadius) : 0\n // 绘制边框\n const background = block.background || _defaultStyle.background\n if (hasBackground(background)) {\n roundRectByArc(ctx, x, y, w, h, r)\n ctx.fillStyle = background\n ctx.fill()\n }\n // 绘制图片\n block.imgs && block.imgs.forEach((imgInfo, imgIndex) => {\n const blockImg = this.ImageCache.get(imgInfo.src)\n if (!blockImg) return\n // 绘制图片\n const [trueWidth, trueHeight] = this.computedWidthAndHeight(blockImg, imgInfo, w, h)\n const [xAxis, yAxis] = [this.getOffsetX(trueWidth, w) + this.getLength(imgInfo.left, w), this.getLength(imgInfo.top, h)]\n this.drawImage(ctx, blockImg, x + xAxis, y + yAxis, trueWidth, trueHeight)\n })\n return {\n x: x + paddingLeft,\n y: y + paddingTop,\n w: w - paddingLeft - paddingRight,\n h: h - paddingTop - paddingBottom\n }\n }, { x: 0, y: 0, w: this.boxWidth, h: this.boxHeight })\n }\n\n /**\n * 绘制老虎机抽奖\n */\n protected draw (): void {\n const { config, ctx, _defaultConfig, _defaultStyle } = this\n // 触发绘制前回调\n config.beforeDraw?.call(this, ctx)\n // 清空画布\n ctx.clearRect(0, 0, this.boxWidth, this.boxHeight)\n // 绘制背景\n const { x, y, w, h } = this.drawBlocks()!\n // 绘制插槽\n if (!this._offscreenCanvas) return\n const { cellWidth, cellHeight, cellAndSpacing, widthAndSpacing, heightAndSpacing } = this\n this.slots.forEach((slot, slotIndex) => {\n // 绘制临界点\n const _p = cellAndSpacing * slot.order!.length\n // 调整奖品垂直居中\n const start = this.displacement(-(h - heightAndSpacing) / 2, -(w - widthAndSpacing) / 2)\n let scroll = this.scroll[slotIndex] + start\n // scroll 会无限累加 1 / -1\n if (scroll < 0) {\n scroll = scroll % _p + _p\n }\n if (scroll > _p) {\n scroll = scroll % _p\n }\n const [sx, sy, sw, sh] = this.displacement(\n [cellWidth * slotIndex, scroll, cellWidth, h],\n [scroll, cellHeight * slotIndex, w, cellHeight]\n )\n const [dx, dy, dw, dh] = this.displacement(\n [x + widthAndSpacing * slotIndex, y, cellWidth, h],\n [x, y + heightAndSpacing * slotIndex, w, cellHeight]\n )\n this.drawImage(ctx, this._offscreenCanvas!, sx, sy, sw, sh, dx, dy, dw, dh)\n })\n }\n\n /**\n * 刻舟求剑\n */\n private carveOnGunwaleOfAMovingBoat (): void {\n const { _defaultConfig, prizeFlag, cellAndSpacing } = this\n // 记录开始停止的时间戳\n this.endTime = Date.now()\n this.slots.forEach((slot, slotIndex) => {\n const order = slot.order!\n if (!order.length) return\n const speed = slot.speed || _defaultConfig.speed\n const direction = slot.direction || _defaultConfig.direction\n const orderIndex = order.findIndex(prizeIndex => prizeIndex === prizeFlag![slotIndex])\n const _p = cellAndSpacing * order.length\n const stopScroll = this.stopScroll[slotIndex] = this.scroll[slotIndex]\n let i = 0\n while (++i) {\n const endScroll = cellAndSpacing * orderIndex + (_p * i * direction) - stopScroll\n const currSpeed = quad.easeOut(this.FPS, stopScroll, endScroll, _defaultConfig.decelerationTime) - stopScroll\n if (Math.abs(currSpeed) > speed) {\n this.endScroll[slotIndex] = endScroll\n break\n }\n }\n })\n }\n\n /**\n * 对外暴露: 开始抽奖方法\n */\n public play (): void {\n if (this.step !== 0) return\n // 记录开始游戏的时间\n this.startTime = Date.now()\n // 清空中奖索引\n this.prizeFlag = void 0\n // 开始加速\n this.step = 1\n // 触发回调\n this.config.afterStart?.()\n // 开始渲染\n this.run()\n }\n\n public stop (index: number | number[]): void {\n if (this.step === 0 || this.step === 3) return\n // 设置中奖索引\n if (typeof index === 'number') {\n this.prizeFlag = new Array(this.slots.length).fill(index)\n } else if (isExpectType(index, 'array')) {\n if (index.length === this.slots.length) {\n this.prizeFlag = index\n } else {\n this.stop(-1)\n return console.error(`stop([${index}]) 参数长度的不正确`)\n }\n } else {\n this.stop(-1)\n return console.error(`stop() 无法识别的参数类型 ${typeof index}`)\n }\n // 如果包含负数则停止游戏, 反之则继续游戏\n if (this.prizeFlag?.includes(-1)) {\n this.prizeFlag = []\n // 停止游戏\n this.step = 0\n } else {\n // 进入匀速\n this.step = 2\n }\n }\n\n /**\n * 让游戏动起来\n * @param num 记录帧动画执行多少次\n */\n private run (num: number = 0): void {\n const { rAF, step, prizeFlag, _defaultConfig, cellAndSpacing, slots } = this\n const { accelerationTime, decelerationTime } = _defaultConfig\n // 游戏结束\n if (this.step === 0 && prizeFlag?.length === slots.length) {\n let flag = prizeFlag[0]\n for (let i = 0; i < slots.length; i++) {\n const slot = slots[i], currFlag = prizeFlag[i]\n if (!slot.order?.includes(currFlag) || flag !== currFlag) {\n flag = -1\n break\n }\n }\n this.endCallback?.(this.prizes.find((prize, index) => index === flag) || void 0)\n return\n }\n // 如果长度为 0 就直接停止游戏\n if (prizeFlag !== void 0 && !prizeFlag.length) return\n // 计算最终停止的位置\n if (this.step === 3 && !this.endScroll.length) this.carveOnGunwaleOfAMovingBoat()\n // 计算时间间隔\n const startInterval = Date.now() - this.startTime\n const endInterval = Date.now() - this.endTime\n // 分别计算对应插槽的加速度\n slots.forEach((slot, slotIndex) => {\n const order = slot.order\n if (!order || !order.length) return\n const _p = cellAndSpacing * order.length\n const speed = Math.abs(slot.speed || _defaultConfig.speed)\n const direction = slot.direction || _defaultConfig.direction\n let scroll = 0, prevScroll = this.scroll[slotIndex]\n if (step === 1 || startInterval < accelerationTime) { // 加速阶段\n // 记录帧率\n this.FPS = startInterval / num\n const currSpeed = quad.easeIn(startInterval, 0, speed, accelerationTime)\n // 加速到最大速度后, 即可进入匀速阶段\n if (currSpeed === speed) {\n this.step = 2\n }\n scroll = (prevScroll + (currSpeed * direction)) % _p\n } else if (step === 2) { // 匀速阶段\n // 速度保持不变\n scroll = (prevScroll + (speed * direction)) % _p\n // 如果有 prizeFlag 有值, 则进入减速阶段\n if (prizeFlag?.length === slots.length) {\n this.step = 3\n // 清空上一轮的位置信息\n this.stopScroll = []\n this.endScroll = []\n }\n } else if (step === 3 && endInterval) { // 减速阶段\n // 开始缓慢停止\n const stopScroll = this.stopScroll[slotIndex]\n const endScroll = this.endScroll[slotIndex]\n scroll = quad.easeOut(endInterval, stopScroll, endScroll, decelerationTime)\n if (endInterval >= decelerationTime) {\n this.step = 0\n }\n }\n this.scroll[slotIndex] = scroll\n })\n this.draw()\n rAF(this.run.bind(this, num + 1))\n }\n\n // 根据mode置换数值\n private displacement<T> (a: T, b: T): T {\n return this._defaultConfig.mode === 'horizontal' ? b : a\n }\n\n // 根据mode计算宽高\n private displacementWidthOrHeight () {\n const mode = this._defaultConfig.mode\n const slotsLen = this.slots.length\n const { colSpacing, rowSpacing } = this._defaultConfig\n const { x, y, w, h } = this.prizeArea || this.drawBlocks()!\n let cellWidth = 0, cellHeight = 0, widthAndSpacing = 0, heightAndSpacing = 0\n if (mode === 'horizontal') {\n cellHeight = this.cellHeight = (h - rowSpacing * (slotsLen - 1)) / slotsLen\n cellWidth = this.cellWidth = cellHeight\n } else {\n cellWidth = this.cellWidth = (w - colSpacing * (slotsLen - 1)) / slotsLen\n cellHeight = this.cellHeight = cellWidth\n }\n widthAndSpacing = this.widthAndSpacing = this.cellWidth + colSpacing\n heightAndSpacing = this.heightAndSpacing = this.cellHeight + rowSpacing\n if (mode === 'horizontal') {\n this.cellAndSpacing = widthAndSpacing\n } else {\n this.cellAndSpacing = heightAndSpacing\n }\n return {\n cellWidth,\n cellHeight,\n widthAndSpacing,\n heightAndSpacing,\n }\n }\n}\n","import { ImgType } from '../types/index'\nimport { roundRectByArc } from './math'\n\n/**\n * 根据路径获取图片对象\n * @param { string } src 图片路径\n * @returns { Promise<HTMLImageElement> } 图片标签\n */\nexport const getImage = (src: string): Promise<ImgType> => {\n return new Promise((resolve, reject) => {\n const img = new Image()\n img.onload = () => resolve(img)\n img.onerror = err => reject(err)\n img.src = src\n })\n}\n\n/**\n * 切割圆角\n * @param img 将要裁剪的图片对象\n * @param radius 裁剪的圆角半径\n * @returns 返回一个离屏 canvas 用于渲染\n */\nexport const cutRound = (img: ImgType, radius: number): ImgType => {\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')!\n const { width, height } = img\n canvas.width = width\n canvas.height = height\n roundRectByArc(ctx, 0, 0, width, height, radius)\n ctx.clip()\n ctx.drawImage(img, 0, 0, width, height)\n return canvas\n}\n\n/**\n * 透明度\n * @param img 将要处理的图片对象\n * @param opacity 透明度\n * @returns 返回一个离屏 canvas 用于渲染\n */\nexport const opacity = (\n img: ImgType,\n opacity: number\n): ImgType => {\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')!\n const { width, height } = img\n canvas.width = width\n canvas.height = height\n // 绘制图片, 部分浏览器不支持 filter 属性, 需要处理兼容\n if (typeof ctx.filter === 'string') {\n ctx.filter = `opacity(${opacity * 100}%)`\n ctx.drawImage(img, 0, 0, width, height)\n } else {\n ctx.drawImage(img, 0, 0, width, height)\n const imageData = ctx.getImageData(0, 0, width, height)\n const { data } = imageData\n const len = data.length\n for (let i = 0; i < len; i += 4) {\n const alpha = data[i + 3]\n if (alpha !== 0) data[i + 3] = alpha * opacity\n }\n ctx.putImageData(imageData, 0, 0)\n }\n return canvas\n}\n\n/**\n * 权重矩阵\n * @param radius 模糊半径\n * @param sigma \n * @returns 返回一个权重和为1的矩阵\n */\nconst getMatrix = (radius: number, sigma?: number): number[] => {\n sigma = sigma || radius / 3\n const r = Math.ceil(radius)\n const sigma_2 = sigma * sigma\n const sigma2_2 = 2 * sigma_2\n const denominator = 1 / (2 * Math.PI * sigma_2)\n const matrix = []\n let total = 0\n // 计算权重矩阵\n for (let x = -r; x <= r; x++) {\n for (let y = -r; y <= r; y++) {\n // 套用二维高斯函数得到每个点的权重\n const res = denominator * Math.exp(-(x * x + y * y) / sigma2_2)\n matrix.push(res)\n total += res\n }\n }\n // 让矩阵中所有权重的和等于1\n for (let i = 0; i < matrix.length; i++) {\n matrix[i] /= total\n }\n return matrix\n}\n\n/**\n * 高斯模糊\n * @param img 将要处理的图片对象\n * @param radius 模糊半径\n * @returns 返回一个离屏 canvas 用于渲染\n */\nexport const blur = (\n img: ImgType,\n radius: number\n): ImgType => {\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')!\n const { width, height } = img\n // 设置图片宽高\n canvas.width = width\n canvas.height = height\n ctx.drawImage(img, 0, 0, width, height)\n const ImageData = ctx.getImageData(0, 0, width, height)\n const { data } = ImageData\n const matrix = getMatrix(radius)\n const r = Math.ceil(radius)\n const w = width * 4\n const cols = r * 2 + 1\n const len = data.length, matrixLen = matrix.length\n for (let i = 0; i < len; i += 4) {\n // 处理\n }\n console.log(ImageData)\n ctx.putImageData(ImageData, 0, 0)\n return canvas\n}\n\nexport const getBase64Image = () => {\n\n}\n"],"names":["Array","prototype","includes","Object","defineProperty","value","valueToFind","fromIndex","this","TypeError","o","len","length","x","y","n","k","Math","max","abs","isNaN","String","search","start","indexOf","find","predicate","thisArg","arguments","kValue","call","isExpectType","param","_i","types","some","type","toString","slice","toLowerCase","has","data","key","hasOwnProperty","removeEnter","str","filter","s","join","hasBackground","color","toLocaleLowerCase","trim","test","alpha","exec","num","NaN","Number","computePadding","block","getLength","padding","split","map","paddingTop","paddingBottom","paddingLeft","paddingRight","res","computeRange","rangeArr","ascendingArr","sum","reduce","prev","curr","push","random","findIndex","splitText","ctx","text","getWidth","lineClamp","Infinity","lines","EndWidth","measureText","width","i","currWidth","maxWidth","subs","Dep","sub","forEach","update","hasProto","def","obj","val","enumerable","writable","configurable","oldArrayProto","newArrayProto","create","method","args","apply","luckyOb","walk","dep","notify","isArray","getOwnPropertyNames","Observer","keys","defineReactive","observe","property","getOwnPropertyDescriptor","getter","get","setter","set","childOb","target","addSub","newVal","uid","$lucky","expr","cb","options","id","deep","path","segments","segment","parsePath","Watcher","dfs","traverse","oldVal","config","el","nodeType","divElement","flag","document","querySelector","canvasElement","createElement","appendChild","getContext","setAttribute","name","addEventListener","e","_this","handleClick","initWindowFunction","console","error","window","fn","wait","timeId","setTimeout","clearTimeout","throttle","resize","MutationObserver","documentElement","attributes","Lucky","beforeResize","setHTMLFontSize","setDpr","resetWidthAndHeight","zoomCanvas","boxWidth","boxHeight","htmlFontSize","getComputedStyle","fontSize","_a","height","clearRect","dpr","devicePixelRatio","offsetWidth","offsetHeight","style","overflow","_b","transform","scale","rAF","requestAnimationFrame","callback","setInterval","clearInterval","timeout_1","src","info","resolveName","Promise","resolve","reject","imgObj_1","Image","onload","onerror","imgObj","drawImg","rectInfo","_c","miniProgramOffCtx","isWeb","temp","getImageData","putImageData","index","drawImage","err","imgInfo","maxHeight","trueWidth","trueHeight","denominator","replace","unit","handleCssUnit","px","rem","vw","innerWidth","otherHandleCssUnit","maxLength","changeUnits","_offscreenCanvas","_ctx","handler","watchOpt","watcher","immediate","getAngle","deg","PI","fanShapedByArc","minRadius","maxRadius","end","gutter","beginPath","r","maxGutter","maxStart","maxEnd","arc","lineTo","sin","cos","toFixed","closePath","roundRectByArc","w","h","min","moveTo","quad","t","b","c","d","_super","Map","initData","initWatch","initComputed","beforeCreate","init","__extends","LuckyWheel","Radius","translate","draw","afterResize","prizeRadius","prizeDeg","prizeAng","rotateDeg","maxBtnRadius","startTime","endTime","stopDeg","endDeg","FPS","prizeFlag","step","initLucky","$set","blocks","prizes","buttons","defaultConfig","defaultStyle","$computed","offsetDegree","speed","speedFunction","accelerationTime","decelerationTime","stopRange","fontColor","fontStyle","fontWeight","background","wordWrap","lengthLimit","$watch","newData","initImageCache","beforeInit","afterInit","willUpdateImgs","imgs","prize","btn","imgName","willUpdate","allPromise","cellIndex","imgIndex","loadAndCacheImg","all","then","isPointInPath","offsetX","offsetY","startCallback","cellName","cell","loadImg","currImg","formatter","ImageCache","catch","radius","blockIndex","fillStyle","fill","blockImg","computedWidthAndHeight","getOffsetX","left","top","xAxis","yAxis","save","rotate","restore","_defaultConfig","_defaultStyle","beforeDraw","drawBlock","shortSide","getFontX","font","line","getFontY","lineIndex","lineHeight","prizeIndex","currMiddleDeg","prizeHeight","prizeImg","fonts","tan","fillText","btnIndex","pointer","btnImg","afterDraw","Date","now","prevSpeed","prevDeg","currSpeed","afterStart","run","item","range","carveOnGunwaleOfAMovingBoat","startInterval","endInterval","stop","bind","endCallback","LuckyGrid","cellWidth","cellHeight","currIndex","stopIndex","endIndex","demo","timer","rows","cols","button","activeStyle","borderRadius","shadow","btnImgs","__spreadArray","getGeometricProperty","col","row","rect","request","defaultImg","activeImg","_activeStyle","cells","prizeArea","handleBackground","isActive","shadowColor","shadowOffsetX","shadowOffsetY","shadowBlur","cellImg","renderImg","size","maxWidth_1","context","shift","direction","getLenOfTanDeg","gradient","createLinearGradient","addColorStop","getLinearGradient","prevIndex","SlotMachine","cellAndSpacing","widthAndSpacing","heightAndSpacing","scroll","stopScroll","endScroll","slots","mode","rowSpacing","colSpacing","drawOffscreenCanvas","drawBlocks","prizesLen","displacementWidthOrHeight","defaultOrder","v","maxOffWidth","maxOffHeight","slot","slotIndex","order","currLen","_d","getOffscreenCanvas","cellX","cellY","lengthOfCopy","newPrizes","arr","getSortedArrayByIndex","prizesX","prizesY","displacement","_x","_y","spacing","_w","_h","drawLen","drawX","drawY","_p","sx","sy","sw","sh","dx","dy","dw","dh","orderIndex","prevScroll","flag_1","currFlag","a","slotsLen","cutRound","img","canvas","clip","opacity","imageData"],"mappings":"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"}