import { reactive, ref, defineComponent, onMounted, onBeforeUnmount, openBlock, createElementBlock, normalizeStyle, createElementVNode, normalizeClass, createCommentVNode, toDisplayString } from "vue"; const PI = Math.PI; function sum(x, y) { return x + y; } function square(x) { return x * x; } function draw(ctx, x, y, l, r, operation) { ctx.beginPath(); ctx.moveTo(x, y); ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI); ctx.lineTo(x + l, y); ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI); ctx.lineTo(x + l, y + l); ctx.lineTo(x, y + l); ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true); ctx.lineTo(x, y); ctx.lineWidth = 2; ctx.fillStyle = "rgba(255, 255, 255, 0.7)"; ctx.strokeStyle = "rgba(255, 255, 255, 0.7)"; ctx.stroke(); ctx[operation](); ctx.globalCompositeOperation = "destination-over"; } function createImg(imgs, onload) { const img = document.createElement("img"); img.crossOrigin = "Anonymous"; img.onload = onload; img.onerror = () => { img.src = getRandomImg(imgs); }; img.src = getRandomImg(imgs); return img; } function getRandomNumberByRange(start, end) { return Math.round(Math.random() * (end - start) + start); } function getRandomImg(imgs) { const len = imgs.length; return len > 0 ? imgs[getRandomNumberByRange(0, len - 1)] : "https://picsum.photos/300/150?image=" + getRandomNumberByRange(0, 1084); } function throttle(fn, interval, options = { leading: true, trailing: true }) { const { leading, trailing, resultCallback } = options; let lastTime = 0; let timer = null; const _throttle = function(...args) { return new Promise((resolve, reject) => { const nowTime = new Date().getTime(); if (!lastTime && !leading) lastTime = nowTime; const remainTime = interval - (nowTime - lastTime); if (remainTime <= 0) { if (timer) { clearTimeout(timer); timer = null; } const result = fn.apply(this, args); if (resultCallback) resultCallback(result); resolve(result); lastTime = nowTime; return; } if (trailing && !timer) { timer = setTimeout(() => { timer = null; lastTime = !leading ? 0 : new Date().getTime(); const result = fn.apply(this, args); if (resultCallback) resultCallback(result); resolve(result); }, remainTime); } }); }; _throttle.cancel = function() { if (timer) clearTimeout(timer); timer = null; lastTime = 0; }; return _throttle; } function useSlideAction() { const origin = reactive({ x: 0, y: 0 }); const success = ref(false); const isMouseDown = ref(false); const timestamp = ref(0); const trail = ref([]); const start = (e) => { if (success.value) return; if (e instanceof MouseEvent) { origin.x = e.clientX; origin.y = e.clientY; } else { origin.x = e.changedTouches[0].pageX; origin.y = e.changedTouches[0].pageY; } isMouseDown.value = true; timestamp.value = Date.now(); }; const move = (w, e, cb) => { if (!isMouseDown.value) return false; let moveX = 0; let moveY = 0; if (e instanceof MouseEvent) { moveX = e.clientX - origin.x; moveY = e.clientY - origin.y; } else { moveX = e.changedTouches[0].pageX - origin.x; moveY = e.changedTouches[0].pageY - origin.y; } if (moveX < 0 || moveX + 38 >= w) return false; cb(moveX); trail.value.push(moveY); }; const verify = (left, blockX, accuracy) => { const arr = trail.value; const average = arr.reduce(sum) / arr.length; const deviations = arr.map((x) => x - average); const stddev = Math.sqrt(deviations.map(square).reduce(sum) / arr.length); const leftNum = parseInt(left); accuracy = accuracy <= 1 ? 1 : accuracy > 10 ? 10 : accuracy; return { spliced: Math.abs(leftNum - blockX) <= accuracy, TuringTest: average !== stddev }; }; const end = (e, cb) => { if (!isMouseDown.value) return false; isMouseDown.value = false; const moveX = e instanceof MouseEvent ? e.clientX : e.changedTouches[0].pageX; if (moveX === origin.x) return false; timestamp.value = Date.now() - timestamp.value; cb(timestamp.value); }; return { origin, success, isMouseDown, timestamp, trail, start, move, end, verify }; } var slideVerify_vue_vue_type_style_index_0_scoped_true_lang = ""; var _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _sfc_main = defineComponent({ name: "SlideVerify", props: { l: { type: Number, default: 42 }, r: { type: Number, default: 10 }, w: { type: Number, default: 310 }, h: { type: Number, default: 155 }, sliderText: { type: String, default: "Slide filled right" }, accuracy: { type: Number, default: 5 }, show: { type: Boolean, default: true }, imgs: { type: Array, default: () => [] }, interval: { type: Number, default: 50 } }, emits: ["success", "again", "fail", "refresh", "imageLoad"], setup(props, { emit }) { const { imgs, l, r, w, h, accuracy, interval } = props; const loadBlock = ref(true); const blockX = ref(0); const blockY = ref(0); const containerCls = reactive({ containerActive: false, containerSuccess: false, containerFail: false }); const sliderBox = reactive({ iconCls: "arrow-right", width: "0", left: "0" }); const block = ref(); const blockCtx = ref(); const canvas = ref(); const canvasCtx = ref(); let img; const { success, start, move, end, verify } = useSlideAction(); const reset = () => { var _a, _b; success.value = false; containerCls.containerActive = false; containerCls.containerSuccess = false; containerCls.containerFail = false; sliderBox.iconCls = "arrow-right"; sliderBox.left = "0"; sliderBox.width = "0"; block.value.style.left = "0"; (_a = canvasCtx.value) == null ? void 0 : _a.clearRect(0, 0, w, h); (_b = blockCtx.value) == null ? void 0 : _b.clearRect(0, 0, w, h); block.value.width = w; img.src = getRandomImg(imgs); }; const refresh = () => { reset(); emit("refresh"); }; function moveCb(moveX) { sliderBox.left = moveX + "px"; let blockLeft = (w - 40 - 20) / (w - 40) * moveX; block.value.style.left = blockLeft + "px"; containerCls.containerActive = true; sliderBox.width = moveX + "px"; } function endCb(timestamp) { const { spliced, TuringTest } = verify(block.value.style.left, blockX.value, accuracy); if (spliced) { if (accuracy === -1) { containerCls.containerSuccess = true; sliderBox.iconCls = "success"; success.value = true; emit("success", timestamp); return; } if (TuringTest) { containerCls.containerSuccess = true; sliderBox.iconCls = "success"; success.value = true; emit("success", timestamp); } else { containerCls.containerFail = true; sliderBox.iconCls = "fail"; emit("again"); } } else { containerCls.containerFail = true; sliderBox.iconCls = "fail"; emit("fail"); } } const touchMoveEvent = throttle((e) => { move(w, e, moveCb); }, interval); const touchEndEvent = (e) => { end(e, endCb); }; onMounted(() => { var _a, _b; const _canvasCtx = (_a = canvas.value) == null ? void 0 : _a.getContext("2d"); const _blockCtx = (_b = block.value) == null ? void 0 : _b.getContext("2d", { willReadFrequently: true }); canvasCtx.value = _canvasCtx; blockCtx.value = _blockCtx; img = createImg(imgs, () => { loadBlock.value = false; const L = l + r * 2 + 3; blockX.value = getRandomNumberByRange(L + 10, w - (L + 10)); blockY.value = getRandomNumberByRange(10 + r * 2, h - (L + 10)); if (_canvasCtx && _blockCtx) { draw(_canvasCtx, blockX.value, blockY.value, l, r, "fill"); draw(_blockCtx, blockX.value, blockY.value, l, r, "clip"); _canvasCtx.drawImage(img, 0, 0, w, h); _blockCtx.drawImage(img, 0, 0, w, h); const _y = blockY.value - r * 2 - 1; const imgData = _blockCtx.getImageData(blockX.value, _y, L, L); block.value.width = L; _blockCtx.putImageData(imgData, 0, _y); } emit('imageLoad') }); document.addEventListener("mousemove", touchMoveEvent); document.addEventListener("mouseup", touchEndEvent); }); onBeforeUnmount(() => { document.removeEventListener("mousemove", touchMoveEvent); document.removeEventListener("mouseup", touchEndEvent); }); return { block, canvas, loadBlock, containerCls, sliderBox, refresh, sliderDown: start, touchStartEvent: start, touchMoveEvent, touchEndEvent }; } }); const _hoisted_1 = ["width", "height"]; const _hoisted_2 = ["width", "height"]; const _hoisted_3 = { class: "slide-verify-slider-text" }; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { return openBlock(), createElementBlock("div", { id: "slideVerify", class: "slide-verify", style: normalizeStyle({ width: _ctx.w + "px" }), onselectstart: "return false;" }, [ createElementVNode("div", { class: normalizeClass({ "slider-verify-loading": _ctx.loadBlock }) }, null, 2), createElementVNode("canvas", { ref: "canvas", width: _ctx.w, height: _ctx.h }, null, 8, _hoisted_1), _ctx.show ? (openBlock(), createElementBlock("div", { key: 0, class: "slide-verify-refresh-icon", onClick: _cache[0] || (_cache[0] = (...args) => _ctx.refresh && _ctx.refresh(...args)) }, _cache[5] || (_cache[5] = [ createElementVNode("i", { class: "iconfont icon-refresh" }, null, -1) ]))) : createCommentVNode("", true), createElementVNode("canvas", { ref: "block", width: _ctx.w, height: _ctx.h, class: "slide-verify-block" }, null, 8, _hoisted_2), createElementVNode("div", { class: normalizeClass(["slide-verify-slider", { "container-active": _ctx.containerCls.containerActive, "container-success": _ctx.containerCls.containerSuccess, "container-fail": _ctx.containerCls.containerFail }]) }, [ createElementVNode("div", { class: "slide-verify-slider-mask", style: normalizeStyle({ width: _ctx.sliderBox.width }) }, [ createElementVNode("div", { class: "slide-verify-slider-mask-item", style: normalizeStyle({ left: _ctx.sliderBox.left }), onMousedown: _cache[1] || (_cache[1] = (...args) => _ctx.sliderDown && _ctx.sliderDown(...args)), onTouchstart: _cache[2] || (_cache[2] = (...args) => _ctx.touchStartEvent && _ctx.touchStartEvent(...args)), onTouchmove: _cache[3] || (_cache[3] = (...args) => _ctx.touchMoveEvent && _ctx.touchMoveEvent(...args)), onTouchend: _cache[4] || (_cache[4] = (...args) => _ctx.touchEndEvent && _ctx.touchEndEvent(...args)) }, [ createElementVNode("i", { class: normalizeClass(["slide-verify-slider-mask-item-icon", "iconfont", `icon-${_ctx.sliderBox.iconCls}`]) }, null, 2) ], 36) ], 4), createElementVNode("span", _hoisted_3, toDisplayString(_ctx.sliderText), 1) ], 2) ], 4); } var SlideVerify = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-3f647794"]]); export { SlideVerify as default };