UNPKG

@oiij/use

Version:

Som Composable Functions for Vue 3

134 lines (132 loc) 4 kB
import { computed, onMounted, ref } from "vue"; import { useEventListener } from "@vueuse/core"; //#region src/composables/use-image-verify.ts function randomNum(min, max) { return Math.floor(Math.random() * (max - min) + min); } function randomColor(min, max) { return `rgb(${randomNum(min, max)},${randomNum(min, max)},${randomNum(min, max)})`; } function drawLine(ctx, width, height, length) { for (let i = 0; i < length; i += 1) { ctx.beginPath(); ctx.moveTo(randomNum(0, width), randomNum(0, height)); ctx.lineTo(randomNum(0, width), randomNum(0, height)); ctx.strokeStyle = randomColor(180, 230); ctx.closePath(); ctx.stroke(); } } function drawPoint(ctx, width, height, length) { for (let i = 0; i < length; i += 1) { ctx.beginPath(); ctx.arc(randomNum(0, width), randomNum(0, height), 1, 0, 2 * Math.PI); ctx.closePath(); ctx.fillStyle = randomColor(150, 200); ctx.fill(); } } function useImageVerify(templateRef, options = { type: "character" }) { const { width = 120, height = 40, refreshOnClick = true, disturbLine = 10, disturbPoint = 40 } = options ?? {}; const value = ref(""); const code = ref(""); const passed = computed(() => value.value.toUpperCase() === code.value.toUpperCase()); function validate() { return new Promise((resolve, reject) => passed.value ? resolve(true) : reject(/* @__PURE__ */ new Error("Failed to verify."))); } function reset() { value.value = ""; } function refresh() { generate(); } function generate() { const _code = _draw(); code.value = _code; return _code; } function _draw() { let imgCode = ""; const ctx = templateRef.value?.getContext("2d"); if (!ctx) return imgCode; ctx.fillStyle = randomColor(180, 230); ctx.fillRect(0, 0, width, height); if (options?.type === "character") { const { length = 4, characterPool = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" } = options?.config ?? {}; for (let i = 0; i < length; i += 1) { const text = characterPool[randomNum(0, characterPool.length)]; imgCode += text; ctx.fillStyle = randomColor(50, 160); ctx.font = `${randomNum(height * 2 / 4, height * 3 / 4)}px SimHei`; ctx.textBaseline = "top"; const x = i * ((width - 10) / length); const y = randomNum(5, height / 4); ctx.fillText(text, x + 5, y); } } if (options?.type === "operation") { const { figure = 10, arith } = options?.config ?? {}; let num1 = Math.floor(Math.random() * figure); let num2 = Math.floor(Math.random() * figure); let codeShow = ""; switch (arith ?? [ "+", "-", "*" ][Math.floor(Math.random() * 3)]) { case "+": imgCode = (num1 + num2).toString(); codeShow = `${num1} + ${num2} = ?`; break; case "-": if (num1 < num2) { const tempNum = num1; num1 = num2; num2 = tempNum; } imgCode = (num1 - num2).toString(); codeShow = `${num1} - ${num2} = ?`; break; case "*": imgCode = (num1 * num2).toString(); codeShow = `${num1} × ${num2} = ?`; break; } for (let i = 0; i < codeShow.length; i += 1) { const text = codeShow[i]; ctx.fillStyle = randomColor(50, 160); ctx.font = `${randomNum(height * 2 / 4, height * 3 / 4)}px SimHei`; ctx.textBaseline = "top"; const x = i * ((width - 10) / codeShow.length); const y = randomNum(5, height / 4); ctx.fillText(text, x + 5, y); } } drawLine(ctx, width, height, disturbLine); drawPoint(ctx, width, height, disturbPoint); return imgCode; } useEventListener(templateRef, "click", () => { if (refreshOnClick) generate(); }); onMounted(() => { if (templateRef.value) { templateRef.value.width = width; templateRef.value.height = height; templateRef.value.style.width = `${width}px`; templateRef.value.style.height = `${height}px`; generate(); } }); return { templateRef, value, code, passed, validate, reset, refresh }; } //#endregion export { useImageVerify };