JavaScript
语言:
JaveScriptBabelCoffeeScript
确定
$(document).ready(function() {
var animating = false;
var $body = $(".demo__body");
var $content = $(".demo__content");
var $line = $(".demo__svg__line");
var $smile = $(".demo__svg__smile");
var $bgPath = $(".demo__svg-bg__path");
var resetD = "M0,0 C125,0 250,0 375,0 S375,0 375,0 L375,667 0,667z";
var smileInit = "M176.61,25 Q187,19 197.39,25";
var smileMid = "M176.61,25 Q187,25 197.39,25";
var smileEnd = "M176.61,25 Q187,34 197.39,25";
var totalLen = $line[0].getTotalLength();
var upperLen = 187;
var circleLen = totalLen - upperLen;
var minLineLen = 60;
var lineDragBoundries = upperLen - minLineLen;
var pullDeltaY = 0;
var pullSlowCoef = 1.2;
var maxPullY = 150;
var minReleaseY = 120;
var contentYCoef = 0.4;
var maxContentY = maxPullY * contentYCoef;
var bodyOffsetX = 0;
var bodyW = $body.outerWidth();
var resetAT = 500;
var releaseStep1AT = 800;
var releaseWaitTime = 3000;
var easings = {
elastic: function(t, b, c, d) {
var ts = (t /= d) * t;
var tc = ts * t;
return b + c * (33 * tc * ts + -106 * ts * ts + 126 * tc + -67 * ts + 15 * t);
},
inCubic: function(t, b, c, d) {
var tc = (t /= d) * t * t;
return b + c * (tc);
}
};
function SvgAddClass(el, cl) {
var regEx = new RegExp('(?:^|\\s)' + cl + '(?!\\S)', "gi");
if (regEx.test(el.attr("class"))) return;
el.attr("class", el.attr("class") + " " + cl);
};
function SvgRemoveClass(el, cl) {
var regEx = new RegExp('(?:^|\\s)' + cl + '(?!\\S)', "gi");
el.attr("class", el.attr("class").replace(regEx, ""));
};
function SvgPathTween(from, to, time, easing) {
var regex = /\d+(\.\d{1,2})?/g;
var fromD = from.attr("d");
var fm = fromD.match(regex);
var tm = to.match(regex);
var diff = [];
for (var i = 0; i < fm.length; i++) {
diff.push(+fm[i] - (+tm[i]));
}
var time = time || 600;
var curFrame = 0;
var frames = time / 1000 * 60;
var easing = easing || "elastic";
function animate() {
if (curFrame > frames) return;
var i = 0;
var newD = fromD.replace(regex, function(m) {
if (+m === 0 || // if nothing changed - skip
i % 2 === 0) { // in this demo I want to animate only y values
i++;
return m;
}
return +easings[easing](curFrame, +fm[i], 0 - diff[i++], frames).toFixed(2);
});
from.attr("d", newD);
curFrame++;
requestAnimationFrame(animate);
};
animate();
};
function pullChange(y, x) {
var pullY = (y <= maxPullY) ? y : maxPullY;
if (pullY < 0) pullY = 0;
var pullCoef = pullY / maxPullY;
var sdo = circleLen + pullCoef * lineDragBoundries;
var pullYCont = +(pullY * contentYCoef).toFixed(2);
var bodyX = parseInt(x - bodyOffsetX, 10);
if (bodyX < 0) bodyX = 0;
if (bodyX > bodyW) bodyX = bodyW;
var leftX = bodyX - 50;
if (leftX < 0) leftX = 0;
var rightX = bodyX + 50;
if (rightX > bodyW) rightX = bodyW;
$body.css("transform", "translate3d(0," + pullY + "px,0)");
$content.css("transform", "translate3d(0," + pullYCont + "px,0)");
$line.css("stroke-dashoffset", sdo);
$bgPath.attr("d", "M0,0 C" + (leftX - 25) + ",0 " + (leftX) + "," + pullYCont + " " + bodyX + "," + pullYCont + " S" + (rightX + 25) + ",0 375,0 L375,667 0,667z");
};
function reset() {
$body.addClass("reset");
$content.addClass("reset");
SvgAddClass($line, "reset");
SvgPathTween($bgPath, resetD);
setTimeout(function() {
$body.removeClass("reset").attr("style", "");
$content.removeClass("reset").attr("style", "");
SvgRemoveClass($line, "reset");
$line.attr("style", "");
animating = false;
}, resetAT);
};
function performMagic() {
$body.addClass("waiting");
SvgAddClass($line, "show-circle");
SvgPathTween($bgPath, resetD);
$content.addClass("reset");
setTimeout(function() {
SvgAddClass($line, "rotating");
}, releaseStep1AT * 0.32);
setTimeout(function() {
$content.removeClass("reset").attr("style", "");
SvgAddClass($smile, "active");
setTimeout(function() {
SvgPathTween($smile, smileMid, 300, "inCubic");
setTimeout(function() {
SvgPathTween($smile, smileEnd, 300, "inCubic");
SvgAddClass($smile, "minified");
}, 500);
}, 700);
}, resetAT);
setTimeout(function() {
SvgRemoveClass($line, "rotating");
SvgRemoveClass($line, "show-circle");
SvgAddClass($line, "reset");
$body.removeClass("waiting").addClass("reset");
setTimeout(function() {
$body.removeClass("reset").attr("style", "");
SvgRemoveClass($line, "reset");
$line.attr("style", "");
SvgRemoveClass($smile, "minified");
SvgRemoveClass($smile, "active");
SvgPathTween($smile, smileInit, 50, "inCubic");
animating = false;
}, resetAT);
}, releaseWaitTime);
};
function release() {
animating = true;
if (pullDeltaY < minReleaseY) {
reset();
} else {
performMagic();
}
};
$(document).on("mousedown touchstart", ".demo__body", function(e) {
if (animating) return;
var startY = e.pageY || e.originalEvent.touches[0].pageY;
bodyOffsetX = $body.offset().left;
$(document).on("mousemove touchmove", function(e) {
var y = e.pageY || e.originalEvent.touches[0].pageY;
var x = e.pageX || e.originalEvent.touches[0].pageX;
pullDeltaY = (y - startY) / pullSlowCoef;
if (!pullDeltaY) return;
pullChange(pullDeltaY, x);
});
$(document).on("mouseup touchend", function() {
$(document).off("mousemove touchmove mouseup touchend");
if (!pullDeltaY) return;
release();
});
});
});