|
var email = document.querySelector('#email'), password = document.querySelector('#password'), mySVG = document.querySelector('.svgContainer'), armL = document.querySelector('.armL'), armR = document.querySelector('.armR'), eyeL = document.querySelector('.eyeL'), eyeR = document.querySelector('.eyeR'), nose = document.querySelector('.nose'), mouth = document.querySelector('.mouth'), mouthBG = document.querySelector('.mouthBG'), mouthSmallBG = document.querySelector('.mouthSmallBG'), mouthMediumBG = document.querySelector('.mouthMediumBG'), mouthLargeBG = document.querySelector('.mouthLargeBG'), mouthMaskPath = document.querySelector('#mouthMaskPath'), mouthOutline = document.querySelector('.mouthOutline'), tooth = document.querySelector('.tooth'), tongue = document.querySelector('.tongue'), chin = document.querySelector('.chin'), face = document.querySelector('.face'), eyebrow = document.querySelector('.eyebrow'), outerEarL = document.querySelector('.earL .outerEar'), outerEarR = document.querySelector('.earR .outerEar'), earHairL = document.querySelector('.earL .earHair'), earHairR = document.querySelector('.earR .earHair'), hair = document.querySelector('.hair'); |
|
var caretPos, curEmailIndex, screenCenter, svgCoords, eyeMaxHorizD = 20, eyeMaxVertD = 10, noseMaxHorizD = 23, noseMaxVertD = 10, dFromC, eyeDistH, eyeLDistV, eyeRDistV, eyeDistR, mouthStatus = "small"; |
|
|
|
function getCoord(e) { |
|
var carPos = email.selectionEnd, |
|
div = document.createElement('div'), |
|
span = document.createElement('span'), |
|
copyStyle = getComputedStyle(email), |
|
emailCoords = {}, caretCoords = {}, centerCoords = {} |
|
; |
|
[].forEach.call(copyStyle, function(prop){ |
|
div.style[prop] = copyStyle[prop]; |
|
}); |
|
div.style.position = 'absolute'; |
|
document.body.appendChild(div); |
|
div.textContent = email.value.substr(0, carPos); |
|
span.textContent = email.value.substr(carPos) || '.'; |
|
div.appendChild(span); |
|
|
|
emailCoords = getPosition(email); //console.log("emailCoords.x: " + emailCoords.x + ", emailCoords.y: " + emailCoords.y); |
|
caretCoords = getPosition(span); //console.log("caretCoords.x " + caretCoords.x + ", caretCoords.y: " + caretCoords.y); |
|
centerCoords = getPosition(mySVG); //console.log("centerCoords.x: " + centerCoords.x); |
|
svgCoords = getPosition(mySVG); |
|
screenCenter = centerCoords.x + (mySVG.offsetWidth / 2); //console.log("screenCenter: " + screenCenter); |
|
caretPos = caretCoords.x + emailCoords.x; //console.log("caretPos: " + caretPos); |
|
|
|
dFromC = screenCenter - caretPos; //console.log("dFromC: " + dFromC); |
|
var pFromC = Math.round((caretPos / screenCenter) * 100) / 100; |
|
if(pFromC < 1) { |
|
|
|
} else if(pFromC > 1) { |
|
pFromC -= 2; |
|
pFromC = Math.abs(pFromC); |
|
} |
|
|
|
eyeDistH = -dFromC * .05; |
|
if(eyeDistH > eyeMaxHorizD) { |
|
eyeDistH = eyeMaxHorizD; |
|
} else if(eyeDistH < -eyeMaxHorizD) { |
|
eyeDistH = -eyeMaxHorizD; |
|
} |
|
|
|
var eyeLCoords = {x: svgCoords.x + 84, y: svgCoords.y + 76}; |
|
var eyeRCoords = {x: svgCoords.x + 113, y: svgCoords.y + 76}; |
|
var noseCoords = {x: svgCoords.x + 97, y: svgCoords.y + 81}; |
|
var mouthCoords = {x: svgCoords.x + 100, y: svgCoords.y + 100}; |
|
var eyeLAngle = getAngle(eyeLCoords.x, eyeLCoords.y, emailCoords.x + caretCoords.x, emailCoords.y + 25); |
|
var eyeLX = Math.cos(eyeLAngle) * eyeMaxHorizD; |
|
var eyeLY = Math.sin(eyeLAngle) * eyeMaxVertD; |
|
var eyeRAngle = getAngle(eyeRCoords.x, eyeRCoords.y, emailCoords.x + caretCoords.x, emailCoords.y + 25); |
|
var eyeRX = Math.cos(eyeRAngle) * eyeMaxHorizD; |
|
var eyeRY = Math.sin(eyeRAngle) * eyeMaxVertD; |
|
var noseAngle = getAngle(noseCoords.x, noseCoords.y, emailCoords.x + caretCoords.x, emailCoords.y + 25); |
|
var noseX = Math.cos(noseAngle) * noseMaxHorizD; |
|
var noseY = Math.sin(noseAngle) * noseMaxVertD; |
|
var mouthAngle = getAngle(mouthCoords.x, mouthCoords.y, emailCoords.x + caretCoords.x, emailCoords.y + 25); |
|
var mouthX = Math.cos(mouthAngle) * noseMaxHorizD; |
|
var mouthY = Math.sin(mouthAngle) * noseMaxVertD; |
|
var mouthR = Math.cos(mouthAngle) * 6; |
|
var chinX = mouthX * .8; |
|
var chinY = mouthY * .5; |
|
var chinS = 1 - ((dFromC * .15) / 100); |
|
if(chinS > 1) {chinS = 1 - (chinS - 1);} |
|
var faceX = mouthX * .3; |
|
var faceY = mouthY * .4; |
|
var faceSkew = Math.cos(mouthAngle) * 5; |
|
var eyebrowSkew = Math.cos(mouthAngle) * 25; |
|
var outerEarX = Math.cos(mouthAngle) * 4; |
|
var outerEarY = Math.cos(mouthAngle) * 5; |
|
var hairX = Math.cos(mouthAngle) * 6; |
|
var hairS = 1.2; |
|
|
|
TweenMax.to(eyeL, 1, {x: -eyeLX , y: -eyeLY, ease: Expo.easeOut}); |
|
TweenMax.to(eyeR, 1, {x: -eyeRX , y: -eyeRY, ease: Expo.easeOut}); |
|
TweenMax.to(nose, 1, {x: -noseX, y: -noseY, rotation: mouthR, transformOrigin: "center center", ease: Expo.easeOut}); |
|
TweenMax.to(mouth, 1, {x: -mouthX , y: -mouthY, rotation: mouthR, transformOrigin: "center center", ease: Expo.easeOut}); |
|
TweenMax.to(chin, 1, {x: -chinX, y: -chinY, scaleY: chinS, ease: Expo.easeOut}); |
|
TweenMax.to(face, 1, {x: -faceX, y: -faceY, skewX: -faceSkew, transformOrigin: "center top", ease: Expo.easeOut}); |
|
TweenMax.to(eyebrow, 1, {x: -faceX, y: -faceY, skewX: -eyebrowSkew, transformOrigin: "center top", ease: Expo.easeOut}); |
|
TweenMax.to(outerEarL, 1, {x: outerEarX, y: -outerEarY, ease: Expo.easeOut}); |
|
TweenMax.to(outerEarR, 1, {x: outerEarX, y: outerEarY, ease: Expo.easeOut}); |
|
TweenMax.to(earHairL, 1, {x: -outerEarX, y: -outerEarY, ease: Expo.easeOut}); |
|
TweenMax.to(earHairR, 1, {x: -outerEarX, y: outerEarY, ease: Expo.easeOut}); |
|
TweenMax.to(hair, 1, {x: hairX, scaleY: hairS, transformOrigin: "center bottom", ease: Expo.easeOut}); |
|
|
|
document.body.removeChild(div); |
|
}; |
|
|
|
function onEmailInput(e) { |
|
getCoord(e); |
|
var value = e.target.value; |
|
curEmailIndex = value.length; |
|
|
|
// very crude email validation for now to trigger effects |
|
if(curEmailIndex > 0) { |
|
if(mouthStatus == "small") { |
|
mouthStatus = "medium"; |
|
TweenMax.to([mouthBG, mouthOutline, mouthMaskPath], 1, {morphSVG: mouthMediumBG, shapeIndex: 8, ease: Expo.easeOut}); |
|
TweenMax.to(tooth, 1, {x: 0, y: 0, ease: Expo.easeOut}); |
|
TweenMax.to(tongue, 1, {x: 0, y: 1, ease: Expo.easeOut}); |
|
TweenMax.to([eyeL, eyeR], 1, {scaleX: .85, scaleY: .85, ease: Expo.easeOut}); |
|
} |
|
if(value.includes("@")) { |
|
mouthStatus = "large"; |
|
TweenMax.to([mouthBG, mouthOutline, mouthMaskPath], 1, {morphSVG: mouthLargeBG, ease: Expo.easeOut}); |
|
TweenMax.to(tooth, 1, {x: 3, y: -2, ease: Expo.easeOut}); |
|
TweenMax.to(tongue, 1, {y: 2, ease: Expo.easeOut}); |
|
TweenMax.to([eyeL, eyeR], 1, {scaleX: .65, scaleY: .65, ease: Expo.easeOut, transformOrigin: "center center"}); |
|
} else { |
|
mouthStatus = "medium"; |
|
TweenMax.to([mouthBG, mouthOutline, mouthMaskPath], 1, {morphSVG: mouthMediumBG, ease: Expo.easeOut}); |
|
TweenMax.to(tooth, 1, {x: 0, y: 0, ease: Expo.easeOut}); |
|
TweenMax.to(tongue, 1, {x: 0, y: 1, ease: Expo.easeOut}); |
|
TweenMax.to([eyeL, eyeR], 1, {scaleX: .85, scaleY: .85, ease: Expo.easeOut}); |
|
} |
|
} else { |
|
mouthStatus = "small"; |
|
TweenMax.to([mouthBG, mouthOutline, mouthMaskPath], 1, {morphSVG: mouthSmallBG, shapeIndex: 9, ease: Expo.easeOut}); |
|
TweenMax.to(tooth, 1, {x: 0, y: 0, ease: Expo.easeOut}); |
|
TweenMax.to(tongue, 1, {y: 0, ease: Expo.easeOut}); |
|
TweenMax.to([eyeL, eyeR], 1, {scaleX: 1, scaleY: 1, ease: Expo.easeOut}); |
|
} |
|
} |
|
|
|
function onEmailFocus(e) { |
|
e.target.parentElement.classList.add("focusWithText"); |
|
getCoord(); |
|
} |
|
|
|
function onEmailBlur(e) { |
|
if(e.target.value == "") { |
|
e.target.parentElement.classList.remove("focusWithText"); |
|
} |
|
resetFace(); |
|
} |
|
|
|
function onPasswordFocus(e) { |
|
coverEyes(); |
|
} |
|
|
|
function onPasswordBlur(e) { |
|
uncoverEyes(); |
|
} |
|
|
|
function coverEyes() { |
|
TweenMax.to(armL, .45, {x: -93, y: 2, rotation: 0, ease: Quad.easeOut}); |
|
TweenMax.to(armR, .45, {x: -93, y: 2, rotation: 0, ease: Quad.easeOut, delay: .1}); |
|
} |
|
|
|
function uncoverEyes() { |
|
TweenMax.to(armL, 1.35, {y: 220, ease: Quad.easeOut}); |
|
TweenMax.to(armL, 1.35, {rotation: 105, ease: Quad.easeOut, delay: .1}); |
|
TweenMax.to(armR, 1.35, {y: 220, ease: Quad.easeOut}); |
|
TweenMax.to(armR, 1.35, {rotation: -105, ease: Quad.easeOut, delay: .1}); |
|
} |
|
|
|
function resetFace() { |
|
TweenMax.to([eyeL, eyeR], 1, {x: 0, y: 0, ease: Expo.easeOut}); |
|
TweenMax.to(nose, 1, {x: 0, y: 0, scaleX: 1, scaleY: 1, ease: Expo.easeOut}); |
|
TweenMax.to(mouth, 1, {x: 0, y: 0, rotation: 0, ease: Expo.easeOut}); |
|
TweenMax.to(chin, 1, {x: 0, y: 0, scaleY: 1, ease: Expo.easeOut}); |
|
TweenMax.to([face, eyebrow], 1, {x: 0, y: 0, skewX: 0, ease: Expo.easeOut}); |
|
TweenMax.to([outerEarL, outerEarR, earHairL, earHairR, hair], 1, {x: 0, y: 0, scaleY: 1, ease: Expo.easeOut}); |
|
} |
|
|
|
function getAngle(x1, y1, x2, y2) { |
|
var angle = Math.atan2(y1 - y2, x1 - x2); |
|
return angle; |
|
} |
|
|
|
function getPosition(el) { |
|
var xPos = 0; |
|
var yPos = 0; |
|
|
|
while (el) { |
|
if (el.tagName == "BODY") { |
|
// deal with browser quirks with body/window/document and page scroll |
|
var xScroll = el.scrollLeft || document.documentElement.scrollLeft; |
|
var yScroll = el.scrollTop || document.documentElement.scrollTop; |
|
|
|
xPos += (el.offsetLeft - xScroll + el.clientLeft); |
|
yPos += (el.offsetTop - yScroll + el.clientTop); |
|
} else { |
|
// for all other non-BODY elements |
|
xPos += (el.offsetLeft - el.scrollLeft + el.clientLeft); |
|
yPos += (el.offsetTop - el.scrollTop + el.clientTop); |
|
} |
|
|
|
el = el.offsetParent; |
|
} |
|
return { |
|
x: xPos, |
|
y: yPos |
|
}; |
|
} |
|
|
|
email.addEventListener('focus', onEmailFocus); |
|
email.addEventListener('blur', onEmailBlur); |
|
email.addEventListener('input', onEmailInput); |
|
password.addEventListener('focus', onPasswordFocus); |
|
password.addEventListener('blur', onPasswordBlur); |
|
TweenMax.set(armL, {x: -93, y: 220, rotation: 105, transformOrigin: "top left"}); |
|
TweenMax.set(armR, {x: -93, y: 220, rotation: -105, transformOrigin: "top right"}); |
this need external javascript resouces so you just need to put this code before closing body tag :
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
the full html page :
`
<title>Login Page</title> <style> .container { width: 90% } /* colors */ html { width: 100%; height: 100%; } body { background-color: #eff3f4; position: relative; width: 100%; height: 100%; font-size: 16px; font-family: 'Source Sans Pro', sans-serif; font-weight: 400; -webkit-font-smoothing: antialiased; } form { position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%); display: block; width: 100%; max-width: 400px; background-color: #FFF; margin: 0; padding: 2.25em; box-sizing: border-box; border: solid 1px #DDD; border-radius: .5em; font-family: 'Source Sans Pro', sans-serif; } form .svgContainer { position: relative; width: 200px; height: 200px; margin: 0 auto 1em; border-radius: 50%; background: none; border: solid 2.5px #3A5E77; overflow: hidden; pointer-events: none; } form .svgContainer div { position: relative; width: 100%; height: 0; overflow: hidden; padding-bottom: 100%; } form .svgContainer .mySVG { position: absolute; left: 0; top: 0; width: 100%; height: 100%; pointer-events: none; } form .inputGroup { margin: 0 0 2em; padding: 0; position: relative; } form .inputGroup:last-of-type { margin-bottom: 0; } form label { margin: 0 0 12px; display: block; font-size: 1.25em; color: #217093; font-weight: 700; font-family: inherit; } form input[type='email'], form input[type="text"], form input[type='password'] { display: block; margin: 0; padding: 0 1em 0; background-color: #f3fafd; border: solid 2px #217093; border-radius: 4px; -webkit-appearance: none; box-sizing: border-box; width: 100%; height: 65px; font-size: 1.55em; color: #353538; font-weight: 600; font-family: inherit; transition: box-shadow .2s linear, border-color .25s ease-out; } form input[type='email']:focus, form input[type="text"]:focus, form input[type='password']:focus { outline: none; box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1); border: solid 2px #4eb8dd; } form input[type='email'], form input[type="text"] { padding: 14px 1em 0px; } form button { display: block; margin: 0; padding: .65em 1em 1em; background-color: #4eb8dd; border: none; border-radius: 4px; box-sizing: border-box; box-shadow: none; width: 100%; height: 65px; font-size: 1.55em; color: #FFF; font-weight: 600; font-family: inherit; transition: background-color .2s ease-out; } form button:hover, form button:active { background-color: #217093; } form .inputGroup1 .helper { position: absolute; z-index: 1; font-family: inherit; } form .inputGroup1 .helper1 { top: 0; left: 0; -webkit-transform: translate(1.4em, 2.6em) scale(1); transform: translate(1.4em, 2.6em) scale(1); -webkit-transform-origin: 0 0; transform-origin: 0 0; color: #217093; font-size: 1.25em; font-weight: 400; opacity: .65; pointer-events: none; transition: opacity .2s linear, -webkit-transform .2s ease-out; transition: transform .2s ease-out, opacity .2s linear; transition: transform .2s ease-out, opacity .2s linear, -webkit-transform .2s ease-out; } form .inputGroup1.focusWithText .helper { /*input[type='email']:focus + .helper {*/ -webkit-transform: translate(1.4em, 2em) scale(0.65); transform: translate(1.4em, 2em) scale(0.65); opacity: 1; } </style>