common-lottery
Version:
A Vue 3 lottery component
171 lines (170 loc) • 6.22 kB
JavaScript
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
};