@oiij/use
Version:
Som Composable Functions for Vue 3
134 lines (132 loc) • 4 kB
JavaScript
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 };