123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- 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 };
|