(function (window) {
|
let l = 50, // 滑块边长
|
r = 0, // 滑块半径
|
w = 300, // canvas宽度
|
h = 150, // canvas高度
|
PI = Math.PI;
|
let L = l + r * 2; // 滑块实际边长
|
|
function createCanvas(width, height) {
|
const canvas = createElement("canvas");
|
canvas.width = width;
|
canvas.height = height;
|
return canvas;
|
}
|
|
function createImg(onload, info) {
|
const img = createElement("img");
|
img.crossOrigin = "Anonymous";
|
img.onload = onload;
|
img.onerror = () => {
|
img.src = getRandomImg(info.backgroundImage);
|
};
|
img.src = getRandomImg(info.backgroundImage);
|
return img;
|
}
|
|
function createImg2(onload, info) {
|
const block = createElement("img");
|
block.crossOrigin = "Anonymous";
|
block.onload = onload;
|
block.onerror = () => {
|
block.src = getRandomImg(info.frontImage);
|
};
|
block.src = getRandomImg(info.frontImage);
|
return block;
|
}
|
|
function createElement(tagName) {
|
return document.createElement(tagName);
|
}
|
|
function addClass(tag, className) {
|
tag.classList.add(className);
|
}
|
|
function removeClass(tag, className) {
|
tag.classList.remove(className);
|
}
|
|
function getRandomImg(val) {
|
return val;
|
}
|
|
function sum(x, y) {
|
return x + y;
|
}
|
|
function square(x) {
|
return x * x;
|
}
|
|
function clear(obj) {
|
obj.canvasCtx.clearRect(0, 0, w, h);
|
obj.blockCtx.clearRect(0, 0, w, h);
|
obj.block.width = w;
|
document.getElementById("msg").innerHTML = null;
|
document.getElementById("captcha").innerHTML = null;
|
}
|
|
class jigsaw {
|
constructor(el, success, fail, info, parent) {
|
this.el = el;
|
this.success = success;
|
this.fail = fail;
|
this.info = info;
|
this.parent = parent;
|
}
|
|
init() {
|
if (this.info) {
|
const { backgroundHeight, backgroundWidth, frontHeight, frontWidth } =
|
this.info;
|
l = frontHeight;
|
r = 0;
|
w = backgroundWidth;
|
h = backgroundHeight;
|
L = frontWidth;
|
}
|
this.initDOM();
|
this.initImg();
|
this.bindEvents();
|
}
|
|
initDOM() {
|
const canvas = createCanvas(w, h); // 画布
|
const block = canvas.cloneNode(true); // 滑块
|
const msg = createElement("div");
|
const sliderContainer = createElement("div");
|
const refreshIcon = createElement("div");
|
const sliderMask = createElement("div");
|
const slider = createElement("div");
|
const sliderIcon = createElement("span");
|
const text = createElement("span");
|
|
block.className = "block";
|
msg.id = "msg";
|
sliderContainer.className = "sliderContainer";
|
refreshIcon.className = "refreshIcon";
|
sliderMask.className = "sliderMask";
|
slider.className = "slider";
|
sliderIcon.className = "sliderIcon";
|
text.innerHTML = "向右滑动滑块填充拼图";
|
text.className = "sliderText";
|
|
const el = this.el;
|
el.appendChild(canvas);
|
el.appendChild(refreshIcon);
|
el.appendChild(block);
|
el.appendChild(msg);
|
slider.appendChild(sliderIcon);
|
sliderMask.appendChild(slider);
|
sliderContainer.appendChild(sliderMask);
|
sliderContainer.appendChild(text);
|
el.appendChild(sliderContainer);
|
|
Object.assign(this, {
|
canvas,
|
block,
|
sliderContainer,
|
refreshIcon,
|
slider,
|
sliderMask,
|
sliderIcon,
|
text,
|
msg,
|
canvasCtx: canvas.getContext("2d"),
|
blockCtx: block.getContext("2d"),
|
addClass,
|
clear,
|
});
|
}
|
|
initImg() {
|
const block = createImg2(() => {
|
this.blockCtx.drawImage(block, 0, 0, w, h);
|
}, this.info);
|
const img = createImg(() => {
|
this.canvasCtx.drawImage(img, 0, 0, w, h);
|
}, this.info);
|
this.img = img;
|
}
|
|
clean() {
|
this.canvasCtx.clearRect(0, 0, w, h);
|
this.blockCtx.clearRect(0, 0, w, h);
|
this.block.width = w;
|
}
|
|
bindEvents() {
|
this.el.onselectstart = () => false;
|
this.refreshIcon.onclick = () => {
|
this.reset();
|
};
|
|
let originX,
|
originY,
|
trail = [],
|
isMouseDown = false;
|
var that = this;
|
|
var handleDragStart = function (e) {
|
originX = e.clientX || e.touches[0].clientX;
|
originY = e.clientY || e.touches[0].clientY;
|
// (originX = e.x), (originY = e.y);
|
isMouseDown = true;
|
};
|
|
var handleDragMove = function (e) {
|
if (!isMouseDown) return false;
|
var eventX = e.clientX || e.touches[0].clientX;
|
var eventY = e.clientY || e.touches[0].clientY;
|
const moveX = eventX - originX;
|
const moveY = eventY - originY;
|
if (moveX < 0 || moveX + 38 >= w) return false;
|
that.slider.style.left = moveX + "px";
|
var blockLeft = ((w - 40 - 20) / (w - 40)) * moveX;
|
that.block.style.left = blockLeft + "px";
|
addClass(that.sliderContainer, "sliderContainer_active");
|
that.sliderMask.style.width = moveX + "px";
|
console.log(that.sliderMask.offsetLeft, 4545);
|
trail.push(moveY);
|
};
|
|
var handleDragEnd = function (e) {
|
if (!isMouseDown) return false;
|
isMouseDown = false;
|
var eventX = e.clientX || e.changedTouches[0].clientX;
|
if (eventX == originX) return false;
|
removeClass(that.sliderContainer, "sliderContainer_active");
|
that.trail = trail;
|
const { left } = that.verify();
|
const { prefix } = that.info;
|
if (left && prefix) {
|
that.success(left, prefix, that);
|
} else {
|
addClass(that.sliderContainer, "sliderContainer_fail");
|
that.fail && that.fail(left, prefix);
|
setTimeout(() => {
|
that.reset();
|
}, 1000);
|
}
|
};
|
this.slider.addEventListener("mousedown", handleDragStart);
|
this.slider.addEventListener("touchstart", handleDragStart);
|
document.addEventListener("mousemove", handleDragMove);
|
document.addEventListener("touchmove", handleDragMove);
|
document.addEventListener("mouseup", handleDragEnd);
|
document.addEventListener("touchend", handleDragEnd);
|
|
document.addEventListener("mousedown", function () {
|
return false;
|
});
|
document.addEventListener("touchstart", function () {
|
return false;
|
});
|
// this.slider.addEventListener("mousedown");
|
// document.addEventListener("mousemove");
|
// document.addEventListener("mouseup");
|
}
|
|
verify() {
|
const arr = this.trail; // 拖动时y轴的移动距离
|
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 left = parseInt(this.block.style.left);
|
return {
|
// spliced: Math.abs(left - this.x) < 10,
|
// TuringTest: average !== stddev, // 只是简单的验证拖动轨迹,相等时一般为0,表示可能非人为操作
|
left,
|
// x: this.x,
|
};
|
}
|
|
reset() {
|
this.sliderContainer.className = "sliderContainer";
|
this.slider.style.left = 0;
|
this.block.style.left = 0;
|
this.sliderMask.style.width = 0;
|
clear(this);
|
// this.initImg();
|
this.parent.getImg();
|
console.log(this.parent);
|
}
|
}
|
|
window.jigsaw = {
|
init: function (element, success, fail, info, callback) {
|
new jigsaw(element, success, fail, info, callback).init();
|
},
|
};
|
})(window);
|