UNPKG

common-lottery

Version:

A Vue 3 lottery component

171 lines (170 loc) 6.22 kB
import { defineComponent as H, ref as k, computed as C, watch as J, openBlock as F, createElementBlock as _, createElementVNode as h, normalizeStyle as z, Fragment as K, renderList as Q, createCommentVNode as X, toDisplayString as T, normalizeClass as ee } from "vue"; const te = { class: "lottery-container" }, ne = { class: "lottery-wheel-wrapper" }, le = ["href", "x", "y"], oe = ["d", "fill"], ae = ["x", "y", "transform"], se = ["disabled"], $ = 2, B = 3e3, re = /* @__PURE__ */ H({ __name: "common-lottery", props: { lotteryConfig: {}, winningId: {} }, emits: ["start", "end", "update:winningId", "stopped"], setup(m, { expose: P, emit: M }) { const p = m, d = M, s = k(!1), u = k(!1), r = k(0); let c = null, a = 8, g = !1, f = null, E = null, D = null, v = null, S = null; const o = C(() => [...p.lotteryConfig.prizeList]), W = [ "#FFD700", "#FFB347", "#FF6961", "#77DD77", "#AEC6CF", "#CBAACB", "#B39EB5", "#779ECB", "#FFB7B2", "#FFDAC1", "#E2F0CB", "#B5EAD7", "#C7CEEA", "#FF9AA2", "#FFCCF9", "#B5B9FF", "#D5AAFF", "#A0E7E5", "#FFAEBC", "#A0E7E5" ], L = C(() => 360 / o.value.length), q = C(() => ({ transform: `rotate(${r.value}deg)`, transition: "none" })); function N(n, e) { const l = 2 * Math.PI / e, t = n * l - Math.PI / 2, y = t + l, i = 180, x = 200 + i * Math.cos(t), A = 200 + i * Math.sin(t), w = 200 + i * Math.cos(y), I = 200 + i * Math.sin(y); return `M200,200 L${x},${A} A${i},${i} 0 0,1 ${w},${I} Z`; } const U = C(() => { const n = o.value.length; let e = 18; return n > 16 ? e = 10 : n > 8 && (e = 14), { fontSize: e + "px", fontWeight: "bold", userSelect: "none" }; }); function V() { s.value || (s.value = !0, u.value = !1, c && clearInterval(c), f && cancelAnimationFrame(f), a = 8, g = !1, c = window.setInterval(() => { r.value = (r.value + a) % 360, a < 12 && (a += 0.1); }, 16), d("update:winningId", void 0), d("start")); } function O() { !s.value || u.value || (u.value = !0, g = !0, c && clearInterval(c), D = a, E = performance.now(), v = null, S && clearTimeout(S), Y(), S = window.setTimeout(() => { v ? (b(v), v = null) : a = $; }, B), d("end")); } function Y() { function n() { if (!g) return; const e = performance.now(), l = e - (E || e); if (l < B) { const t = l / B; a = (D || 8) - ((D || 8) - $) * t; } else a = $; r.value = (r.value + a) % 360, f = requestAnimationFrame(n); } n(); } function Z() { s.value ? u.value || O() : V(); } J(() => p.winningId, (n) => { if (!s.value || !u.value || !n) return; const e = performance.now(); e - (E || e) < B ? v = n : b(n); }); function b(n) { g = !1, f && cancelAnimationFrame(f); const e = o.value.findIndex((w) => w.id === n); if (e === -1) return; const l = 360 - (e * L.value + L.value / 2); let t = r.value % 360, y = (l - t + 360) % 360, i = y / a * 16; const x = performance.now(); function A(w) { const I = w - x; if (I >= i) { r.value = l, s.value = !1, u.value = !1, d("stopped"); return; } const G = I / i; r.value = t + y * G, requestAnimationFrame(A); } requestAnimationFrame(A); } function j() { s.value = !1, u.value = !1, r.value = 0, c && clearInterval(c), f && cancelAnimationFrame(f), a = 8, g = !1, v = null; } return P({ reset: j }), (n, e) => (F(), _("div", te, [ h("div", ne, [ e[1] || (e[1] = h("div", { class: "lottery-pointer" }, null, -1)), (F(), _("svg", { class: "lottery-wheel", style: z(q.value), viewBox: "0 0 400 400", width: "100%", height: "100%", preserveAspectRatio: "xMidYMid meet" }, [ (F(!0), _(K, null, Q(o.value, (l, t) => (F(), _("g", { key: l.id }, [ l.iconUrl ? (F(), _("image", { key: 0, href: l.iconUrl, x: 200 + 110 * Math.cos((t + 0.5) * 2 * Math.PI / o.value.length - Math.PI / 2) - 20, y: 200 + 110 * Math.sin((t + 0.5) * 2 * Math.PI / o.value.length - Math.PI / 2) - 40, width: "40", height: "40", style: { "pointer-events": "none" } }, null, 8, le)) : X("", !0), h("path", { d: N(t, o.value.length), fill: W[t % 20], stroke: "#fff", "stroke-width": "2" }, null, 8, oe), h("text", { x: 200 + 110 * Math.cos((t + 0.5) * 2 * Math.PI / o.value.length - Math.PI / 2), y: 200 + 110 * Math.sin((t + 0.5) * 2 * Math.PI / o.value.length - Math.PI / 2), "text-anchor": "middle", "alignment-baseline": "middle", transform: `rotate(${(t + 0.5) * 360 / o.value.length},${200 + 110 * Math.cos((t + 0.5) * 2 * Math.PI / o.value.length - Math.PI / 2)},${200 + 110 * Math.sin((t + 0.5) * 2 * Math.PI / o.value.length - Math.PI / 2)})`, class: "prize-name", style: z(U.value) }, T(l.name), 13, ae) ]))), 128)), e[0] || (e[0] = h("circle", { cx: "200", cy: "200", r: "30", fill: "#fff", stroke: "#eee", "stroke-width": "4" }, null, -1)) ], 4)) ]), h("button", { class: ee(["lottery-button", { running: s.value }]), onClick: Z, disabled: !p.lotteryConfig.canLottery }, T(s.value ? "结束抽奖" : "点击抽奖"), 11, se) ])); } }); const ie = (m, P) => { const M = m.__vccOpts || m; for (const [p, d] of P) M[p] = d; return M; }, R = /* @__PURE__ */ ie(re, [["__scopeId", "data-v-efb40495"]]); R.install = (m) => { m.component("CommonLottery", R); }; export { R as CommonLottery, R as default };