Звёздный рейтинг
Звездный рейтинг с svg анимацией настроений вымышленного инопланетянина. Звезды представляют из себя radio элементы формы, а анимация выполнена с использованием js GreenSock
HTML
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display: none;">
<symbol id="star" viewBox="0 0 48 45.7">
<path d="M24 37.9L9.2 45.7 12 29.1 0 17.4 16.6 15 24 0l7.4 15L48 17.4 36 29.1l2.8 16.6z"/>
</symbol>
<symbol id="no-rating" viewBox="0 0 44 44">
<path d="M22 0C9.9 0 0 9.9 0 22s9.9 22 22 22 22-9.9 22-22S34.1 0 22 0zm16 22c0 3.3-1 6.4-2.8 9L13 8.8C15.6 7 18.7 6 22 6c8.8 0 16 7.2 16 16zM6 22c0-3.3 1-6.4 2.8-9L31 35.2C28.4 37 25.3 38 22 38c-8.8 0-16-7.2-16-16z"/>
</symbol>
</svg>
<form action="#" method="post">
<fieldset class="rate-radios">
<legend>How would you rate the product?</legend>
<div id="avatar" aria-hidden="true" style="opacity: 0;">
<div>
<svg xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 350 350" width="200">
<defs>
<clipPath id="eye-clip">
<path id="eye-clippath" class="eye-path" fill="none" d="M211 76.91c-11.42.47-23.35.71-35.63.71s-24.21-.24-35.63-.71a39.82 39.82 0 00-4.37 18.18 40.25 40.25 0 001.16 9.57c12.39-.55 25.41-.85 38.84-.85s26.45.3 38.84.85a40.25 40.25 0 001.16-9.57A39.82 39.82 0 00211 76.91z"/>
</clipPath>
<clipPath id="mouth-clip">
<path id="mouth-clippath" class="mouth-path" fill="none" d="M147.32 165.64h56.12a8.94 8.94 0 018.94 8.94 33.06 33.06 0 01-33.06 33.06h-7.88a33.06 33.06 0 01-33.06-33.06 8.94 8.94 0 018.94-8.94z"/>
</clipPath>
</defs>
<circle cx="175" cy="175" r="175" fill="#F8EDFF"/>
<g id="ear-l">
<circle cx="66.93" cy="137.42" r="40" fill="#e7cafa" stroke="#62457a" stroke-linecap="round" stroke-width="5"/>
<path fill="#e7cafa" stroke="#62457a" stroke-linecap="round" stroke-width="5" d="M64.55 123a14.39 14.39 0 000 28.78"/>
</g>
<g id="ear-r">
<circle cx="283.07" cy="137.42" r="40" fill="#e7cafa" stroke="#62457a" stroke-linecap="round" stroke-width="5"/>
<path fill="#e7cafa" stroke="#62457a" stroke-linecap="round" stroke-width="5" d="M285.45 123a14.39 14.39 0 010 28.78"/>
</g>
<rect id="earring" width="12" height="30" x="284.65" y="169.64" fill="#faf18f" stroke="#62457a" stroke-linecap="round" stroke-width="4.73" rx="6"/>
<path id="horn-2" fill="#f0a6df" stroke="#62457a" stroke-linecap="round" stroke-width="5" d="M224.58 46.46A98.05 98.05 0 01229-1.46 3.94 3.94 0 00223-6a61.34 61.34 0 00-21.44 27.72c-.57 0-2.22 12.57 5.64 20a19.76 19.76 0 0017.38 4.74z"/>
<path id="horn-1" fill="#f0a6df" stroke="#62457a" stroke-linecap="round" stroke-width="5" d="M122.5 46.46a97.93 97.93 0 00-4.41-47.92 3.94 3.94 0 016-4.53 61.32 61.32 0 0121.43 27.72c.57 0 2.22 12.57-5.64 20a19.76 19.76 0 01-17.38 4.73z"/>
<path fill="#A45CE0" d="M275 118.7c0-54.6-44.7-101-99.3-101.3C120.1 17 75 61.9 75 117.3v44.5c0 46-9.6 91.1-27.8 132.7C79.1 328.7 124.6 350 175 350s95.9-21.3 127.8-55.5C284.6 253 275 207.8 275 161.9v-43.2z"/>
<path fill="none" stroke="#62457A" stroke-linecap="round" stroke-linejoin="round" stroke-width="5" d="M302.8 294.5C284.6 253 275 207.8 275 161.9v-43.2c0-54.6-44.7-101-99.3-101.3C120.1 17 75 61.9 75 117.3v44.5c0 46-9.6 91.1-27.8 132.7"/>
<path id="horn-5" fill="#f0a6df" stroke="#62457a" stroke-linecap="round" stroke-width="5" d="M169.31-24.43l-8.77 51.28a15.57 15.57 0 0026 0l-8.77-51.28a4.29 4.29 0 00-8.46 0z"/>
<path id="horn-4" fill="#f0a6df" stroke="#62457a" stroke-linecap="round" stroke-width="5" d="M253.74 61.74c2.54-14.44 6.9-25.16 15.5-36.94a4 4 0 00-4.52-6c-11.41 3.88-26.8 15.66-34.48 25.2a15.39 15.39 0 004.39 16 24.18 24.18 0 0013.12 6.1 5.3 5.3 0 005.99-4.36z"/>
<path id="horn-3" fill="#f0a6df" stroke="#62457a" stroke-linecap="round" stroke-width="5" d="M93.34 61.74c-2.54-14.44-6.9-25.16-15.5-36.94a4 4 0 014.52-6c11.41 3.88 26.8 15.66 34.48 25.2a15.39 15.39 0 01-4.39 16 24.18 24.18 0 01-13.12 6.1 5.3 5.3 0 01-5.99-4.36z"/>
<g id="nose">
<circle cx="168.38" cy="147.81" r="3.5" fill="#62457a"/>
<circle cx="182.38" cy="147.81" r="3.5" fill="#62457a"/>
</g>
<path id="chin" fill="#a45ce0" stroke="#62457a" stroke-linecap="round" stroke-linejoin="round" stroke-width="5" d="M150.38 215.64a12.59 12.59 0 0011.87 8.36h1.26a12.59 12.59 0 0011.87-8.39 12.59 12.59 0 0011.87 8.39h1.26a12.59 12.59 0 0011.87-8.39"/>
<path id="eye-bg" class="eye-path" fill="#fff" d="M211 76.91c-11.42.47-23.35.71-35.63.71s-24.21-.24-35.63-.71a39.82 39.82 0 00-4.37 18.18 40.25 40.25 0 001.16 9.57c12.39-.55 25.41-.85 38.84-.85s26.45.3 38.84.85a40.25 40.25 0 001.16-9.57A39.82 39.82 0 00211 76.91z"/>
<g id="eye" clip-path="url(#eye-clip)">
<g id="pupil">
<circle cx="175.38" cy="95.09" r="25" fill="#ace4eb"/>
<circle cx="175.38" cy="95.09" r="15" fill="#62457a"/>
<circle cx="168.95" cy="84.37" r="4.29" fill="#fff"/>
</g>
</g>
<path id="eye-outline" class="eye-path" fill="none" stroke="#62457a" stroke-linecap="round" stroke-linejoin="round" stroke-width="5" d="M211 76.91c-11.42.47-23.35.71-35.63.71s-24.21-.24-35.63-.71a39.82 39.82 0 00-4.37 18.18 40.25 40.25 0 001.16 9.57c12.39-.55 25.41-.85 38.84-.85s26.45.3 38.84.85a40.25 40.25 0 001.16-9.57A39.82 39.82 0 00211 76.91z"/>
<path id="mouth-bg" class="mouth-path" fill="#775196" d="M179.32 207.64h-7.88a33 33 0 01-33.06-33.06 8.94 8.94 0 018.94-8.94h56.12a8.94 8.94 0 018.94 8.94 33 33 0 01-33.06 33.06z"/>
<g id="mouth" clip-path="url(#mouth-clip)">
<g id="tongue">
<circle cx="175.61" cy="204.34" r="16" fill="#e3468a"/>
<ellipse cx="175.61" cy="191.34" fill="#fff" opacity=".1" rx="6" ry="3"/>
</g>
<path id="tooth-bot" fill="#fff" d="M160.95 200.64h4a4 4 0 014 4v7h-12v-7a4 4 0 014-4z"/>
<path id="tooth-top" fill="#fff" d="M177.95 161.64h16v9a4 4 0 01-4 4h-8a4 4 0 01-4-4v-9z"/>
</g>
<path id="mouth-outline" class="mouth-path" fill="none" stroke="#62457a" stroke-linecap="round" stroke-linejoin="round" stroke-width="5" d="M179.32 207.64h-7.88a33 33 0 01-33.06-33.06h0a8.94 8.94 0 018.94-8.94h56.12a8.94 8.94 0 018.94 8.94h0a33 33 0 01-33.06 33.06z"/>
</svg>
</div>
</div>
<input checked type="radio" name="rate-input" id="rate-input_0" data-num="0">
<label for="rate-input_0" class="rate-radio rate-radio--none">
<svg aria-hidden="true" focusable="false">
<use xlink:href="#no-rating"/>
</svg>
<span role="presentation">No rating</span>
</label>
<input type="radio" name="rate-input" id="rate-input_1" data-num="1">
<label for="rate-input_1" class="rate-radio">
<svg aria-hidden="true" focusable="false">
<use xlink:href="#star"/>
</svg>
<span role="presentation">1 Star</span>
</label>
<input type="radio" name="rate-input" id="rate-input_2" data-num="2">
<label for="rate-input_2" class="rate-radio">
<svg aria-hidden="true" focusable="false">
<use xlink:href="#star"/>
</svg>
<span role="presentation">2 Stars</span>
</label>
<input type="radio" name="rate-input" id="rate-input_3" data-num="3">
<label for="rate-input_3" class="rate-radio">
<svg aria-hidden="true" focusable="false">
<use xlink:href="#star"/>
</svg>
<span role="presentation">3 Stars</span>
</label>
<input type="radio" name="rate-input" id="rate-input_4" data-num="4">
<label for="rate-input_4" class="rate-radio">
<svg aria-hidden="true" focusable="false">
<use xlink:href="#star"/>
</svg>
<span role="presentation">4 Stars</span>
</label>
<input type="radio" name="rate-input" id="rate-input_5" data-num="5">
<label for="rate-input_5" class="rate-radio">
<svg aria-hidden="true" focusable="false">
<use xlink:href="#star"/>
</svg>
<span role="presentation">5 Stars</span>
</label>
</fieldset>
</form>
SCSS
@import url('https://rsms.me/inter/inter.css');
body, html {width: 100%; height: 100%; font-family: 'Inter', sans-serif;}
body * {box-sizing: border-box;}
:root {
--purple-bare: #F8EDFF;
--purple-light: #e7cafa;
--purple-core: #7E26C8;
--purple-dark: #62457a;
--red: #e3468a;
--red-dark: #9e1852;
--gold: #faf18f;
}
form {
width: 100%; height: 100%;
display: flex; justify-content: center; align-items: center;
}
symbol {overflow: visible;}
legend {
margin: 0 0 1.5em;
display: block; width: 100%;
font-size: 1.25em; font-weight: 700; text-align: center;
color: var(--purple-core);
}
#avatar {
margin: 0 auto 1em;
width: 150px;
div {
position: relative;
width: 100%; height: 0;
padding-bottom: 100%;
svg {
position: absolute;
width: 100%; height: 100%;
overflow: visible;
}
}
}
input[type="radio"] {
/* Visually hide radio buttons while still allowing them to receive keyboard focus. */
position: absolute; top: auto; z-index: 2;
width: 1.5em; height: 2em;
-webkit-appearance: none; -moz-appearance: none; appearance: none;
opacity: .0001;
}
.rate-radio {
margin: 0 .5em 0 0;
position: relative;
display: inline-block; vertical-align: top;
color: #2a2a2a; line-height: 1;
&:last-of-type {margin-right: 0;}
svg {
display: block;
width: 3em; height: 2.85em;
fill: var(--purple-bare);
stroke: #000; stroke-width: 3px; stroke-linejoin: round;
transform: scale(.625);
transition: transform .2s ease-in-out;
overflow: visible;
}
span {
padding: .4em .5em;
position: absolute; left: 50%; top: 100%;
background: #333; border: solid 2px var(--purple-dark); border-radius: .25em;
color: #fff; font-size: .8em; font-weight: 600;
text-align: center; white-space: nowrap;
opacity: 0;
transform: translateY(.5em) translateX(-50%) scale(0);
transition:
opacity .25s ease-in-out,
transform .25s ease-in-out
;
&::before {
content: "";
position: absolute; top: 0; left: 0; z-index: -1;
width: 100%; height: 100%;
border-radius: inherit;
background: var(--purple-core);
opacity: 0;
transition: opacity .25s ease;
}
}
@media (prefers-reduced-motion: reduce) {
svg {
transform: none;
transition: transform .5s ease-in-out;
}
span {
transform: translateY(.5em) translateX(-50%);
transition:
opacity .5s ease-in-out,
transform .5s ease-in-out
;
}
}
}
.rate-radio--none {
svg {
width: 2.85em; height: 2.85em;
fill: #FFF; stroke: var(--red-dark);
}
span {}
}
input:focus + .rate-radio {
outline: dotted .25em #CCC; outline-offset: .5em;
}
fieldset:not([disabled]) input:not([disabled]):hover + .rate-radio span,
.rate-radio:hover span,
input:focus + .rate-radio span {
opacity: 1;
transform: translateY(.5em) translateX(-50%) scale(1);
}
fieldset:not([disabled]) input:not([disabled]):checked + .rate-radio span,
.rate-radio:checked span,
input:checked + .rate-radio span {
opacity: 1;
background: var(--purple-core);
transform: translateY(.5em) translateX(-50%) scale(1);
&::before {opacity: 1;}
}
input:checked + .rate-radio span {
background: #333;
border: 2px solid var(--purple-dark);
}
input:checked + .rate-radio--none span {
}
/**
* Set any rating icon that appears in the DOM, AFTER the checked input as appearing unselected.
* If no input was checked by default, the first radio item will be auto selected, and that's the "none" option
*/
input:checked ~ .rate-radio svg {
fill: var(--purple-bare);
transform: scale(.625);
@media (prefers-reduced-motion: reduce) {
transform: none;
}
}
/**
* If the no-rating option isn't checked get it to look all unselected again
*/
input:not(:checked) ~ .rate-radio--none svg {
fill: var(--purple-dark);
transform: scale(.625);
@media (prefers-reduced-motion: reduce) {
transform: none;
}
}
/**
* The selectors that create the "selected" styling for the actual checked input, and the inputs previous to it in the DOM.
*/
.rate-radio svg,
input:checked + .rate-radio svg {
fill: var(--gold); stroke: var(--purple-dark);
transform: scale(1) translateY(-.25em);
@media (prefers-reduced-motion: reduce) {
transform: none;
}
}
/**
* Coloring for when the "no rating" selection is currently active
*/
input:checked + .rate-radio--none svg {
fill: var(--red); stroke: var(--red-dark);
transform: scale(1);
}
JS
Для анимации используется библиотека GSAP с плагином плавного перехода svg фигуры в другую фигуру:https://cdnjs.cloudflare.com/ajax/libs/gsap/3.0.5/gsap.min.js
https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/MorphSVGPlugin3.min.js
скрипт:console.clear();
/* selector functions */
const $ = (s, o = document) => o.querySelector(s);
const $$ = (s, o = document) => o.querySelectorAll(s);
/* store references to all of the elements we'll need */
const inputs = $$('input[type="radio"]');
const horn1 = $('#horn-1'), horn2 = $('#horn-2'), horn3 = $('#horn-3'), horn4 = $('#horn-4'), horn5 = $('#horn-5');
const earL = $('#ear-l'), earR = $('#ear-r'), earring = $('#earring');
const pupil = $('#pupil');
const eyePaths = $$('.eye-path'), mouthPaths = $$('.mouth-path');
const chin = $('#chin'), tongue = $('#tongue'), toothTop = $('#tooth-top'), toothBot = $('#tooth-bot');
const avatar = $('#avatar');
/* path data for shape morphing */
const eye0 = "M175.4,75.3c-12,0-23.4-0.9-33.7-2.5c-4.2,6.4-6.7,14-6.7,22.2c0,12.4,5.7,23.5,14.6,30.9c6.9,5.7,15.8,9.1,25.4,9.1c9.7,0,18.5-3.4,25.4-9.1c8.9-7.3,14.6-18.4,14.6-30.9c0-8.2-2.5-15.8-6.7-22.1C198.3,74.5,187.1,75.3,175.4,75.3z";
const eye1 = "M213.3,82.3c-9.7,4-23.1,6.5-37.9,6.5s-28.2-2.5-37.9-6.5c-1.3,4-2.1,8.3-2.1,12.8c0,11,4.4,20.9,11.6,28.1c8.2-1.8,18-2.9,28.4-2.9s20.2,1.1,28.4,2.9c7.2-7.2,11.6-17.2,11.6-28.1C215.4,90.6,214.6,86.3,213.3,82.3z";
const eye2 = "M215.4,95.1c0-7.4-2-14.3-5.5-20.3c-9.3,2.5-21.3,4-34.5,4s-25.1-1.5-34.5-4c-3.5,6-5.5,12.9-5.5,20.3c0,13.1,6.3,24.7,16,32c7.2-1.1,15.4-1.7,24-1.7s16.8,0.6,24,1.7C209.1,119.8,215.4,108.2,215.4,95.1z";
const eye3 = "M152.9,128.2c6.8-0.9,14.5-1.5,22.5-1.5s15.7,0.5,22.5,1.5c10.6-7.2,17.5-19.3,17.5-33.1c0-12.8-6-24.2-15.4-31.5c-7.4,2-15.7,3.2-24.6,3.2s-17.3-1.2-24.6-3.2c-9.4,7.3-15.4,18.7-15.4,31.5C135.4,108.8,142.3,121,152.9,128.2z";
const eye4 = "M150.7,128.1c7.3-1.1,15.6-1.7,24.3-1.7s17,0.6,24.3,1.7c10.1-7.5,16.7-19.5,16.7-33c0-13.4-6.4-25.3-16.4-32.8c-6.9-5.2-15.4-8.2-24.6-8.2c-9.5,0-18.2,3.2-25.2,8.6c-9.6,7.5-15.8,19.2-15.8,32.4C134,108.6,140.6,120.6,150.7,128.1z";
const eye5 = "M219,95.1c0,12-4.7,23-12.4,30.9c-7.9,8.1-19,13.1-31.6,13.1c-12.2,0-23.2-4.9-31.1-12.9c-8-8-12.9-19-12.9-31.1c0-13.7,6.2-25.9,16-34c7.6-6.3,17.4-10,28-10c9.9,0,19.1,3.3,26.4,8.8C212.1,67.9,219,80.7,219,95.1z";
const mouth0 = "M174.6,178.2h5.1H215c0,0,0.1,0,0.1,0c0,0,0,0-0.1,0h-35.3L174.6,178.2l-4.6,0.1h-35c0,0-0.1,0-0.1,0c0,0,0,0,0.1,0h35H174.6z";
const mouth1 = "M175,172.6h7c8.9,0,16.2,6.4,17.7,14.9c0.2,1,0.3,2,0.3,3.1c0,0.8-0.5,2-2,2l-16,0h-7h-7l-16,0c-1.4,0-2-1.2-2-2c0-1,0.1-1.9,0.2-2.8c1.4-8.6,8.8-15.1,17.7-15.1H175z";
const mouth2 = "M175,187c5.5,0,9.7-2.1,13.8-4.1c5.5-2.7,11.3-5.5,17.6-0.4c0.1,0.1,0.3,0.3,0.2,0.4c-0.1,0.1-0.3,0.1-0.4,0c-5.6-5.1-11.7-2.6-17.4,0.2c-4.2,2-7.3,4.1-13.9,4.1c-6.5,0-9-2.1-12.9-4.1c-5.1-2.8-10.6-5.8-18.6-0.6c-0.1,0-0.1,0-0.1,0c0,0,0-0.1,0.1-0.1c7.9-5.4,13.4-2.4,18.8,0.5C165.9,185,169.7,187,175,187z";
const mouth3 = "M175,179.8c2,0,4-0.1,6-0.2c11-0.9,22-4.1,32.9-9.7c0.1,0,0.2-0.1,0.2,0c0,0.1-0.1,0.2-0.2,0.2c-11.6,6-21.7,9-33,9.7c-2,0.1-4,0.3-6,0.3c-2.3,0-4.6-0.1-6.8-0.3c-10.9-0.8-20.8-3.9-32.1-9.7c-0.1,0-0.1-0.1-0.1-0.1c0,0,0.1,0,0.2,0c10.7,5.5,21.4,8.7,32.1,9.6C170.5,179.7,172.7,179.8,175,179.8z";
const mouth4 = "M174.8,172.6h10H200l0,4.9c0,1.4-0.2,2.7-0.6,4c-1.8,5.9-7.5,10.1-14.3,10.1h-10.4h-9.9c-6.7,0-12.3-4.2-14.2-9.9c-0.4-1.3-0.7-2.7-0.7-4.2v-4.9h14.3H174.8z";
const mouth5 = "M175,165.6h4.8l23.3,0c5.6,0,8.9,4.7,8.9,8.9c0,3-0.4,6-1.2,8.7c-3.8,14-16.7,24.3-31.9,24.3H175h-3.9c-15.5,0-28.6-10.7-32.1-25.2c-0.6-2.5-0.9-5.2-0.9-7.9c0-5,4.1-8.9,8.9-8.9l23.9,0H175z";
/* vars */
let curRating = 0;
let tl;
let durReduced = 0, durNoPref = .5, dur;
let eyeTarg, mouthTarg, chinY, pupilS, earS, earY, earRotL, earRotR, earringX, earringY, tongueY, toothTopY, toothBotY;
const horns = [horn1,horn2,horn3,horn4,horn5];
let hornsU = [], hornsD = horns;
let mq;
// set up matchMedia instance to detect the reduced motion media query
mq = window.matchMedia('(prefers-reduced-motion: reduce)');
// safari doesn't support 'matchMedia.addEventListener' so we have to check support for that and add the legacy 'addListener' if not.
if(mq.addEventListener) {
mq.addEventListener('change', onReduceMotionMQ);
} else {
mq.addListener(onReduceMotionMQ);
}
// manually check media query initially
onReduceMotionMQ();
// activate any gsap plugins
gsap.registerPlugin(MorphSVGPlugin);
// set initial visual properties of avatar
gsap.set(earL, {transformOrigin: "40px 40px", rotate: "-15deg", y: 10, scale: .9});
gsap.set(earR, {transformOrigin: "40px 40px", rotate: "15deg", y: 10, scale: .9});
gsap.set(earring, {transformOrigin: "50% 0", x: -12, y: 8});
gsap.set(pupil, {transformOrigin: "50% 50%"});
gsap.set(eyePaths, {morphSVG: eye0});
gsap.set(mouthPaths, {morphSVG: mouth0});
gsap.set(chin, {y: 0});
gsap.set(horn1, {transformOrigin: "20px 45px", scale: 0});
gsap.set(horn2, {transformOrigin: "12px 45px", scale: 0});
gsap.set(horn3, {transformOrigin: "32px 38px", scale: 0});
gsap.set(horn4, {transformOrigin: "12px 38px", scale: 0});
gsap.set(horn5, {transformOrigin: "50% 90%", scale: 0});
gsap.set(avatar, {opacity: 1});
/* add click handler to inputs */
inputs.forEach(function(i) {
i.addEventListener("click", onRatingClick);
});
function onRatingClick(e) {
// determine which rating was clicked
let num = parseInt(e.target.getAttribute('data-num'));
// crate new timeline
tl = gsap.timeline({paused: true, defaults:{duration: dur, ease: "sine.out"}});
// determine which horns go up/down
hornsU = horns.slice(0,num);
if(hornsU.length > curRating) {hornsU = hornsU.slice(curRating);}
hornsD = horns.slice(num,curRating);
// set props based on which rating was clicked on
switch (num) {
case 0:
eyeTarg = eye0;
mouthTarg = mouth0;
chinY = 0;
pupilS = 1;
earS = .9; earY = 10; earRotL = "-15deg"; earRotR = "15deg"; earringX = -12; earringY = 8;
tongueY = 0; toothTopY = 0; toothBotY = 0;
break;
case 1:
eyeTarg = eye1;
mouthTarg = mouth1;
chinY = 3;
pupilS = .84;
earS = 1.1; earY = -4; earRotL = "10deg"; earRotR = "-10deg"; earringX = 0; earringY = 0;
tongueY = 2; toothTopY = 5; toothBotY = -17;
break;
case 2:
eyeTarg = eye2;
mouthTarg = mouth2;
chinY = -2;
pupilS = .94;
earS = 1.05; earY = -2; earRotL = "5deg"; earRotR = "-5deg"; earringX = -2; earringY = -1;
tongueY = 0; toothTopY = 0; toothBotY = 0;
break;
case 3:
eyeTarg = eye3;
mouthTarg = mouth3;
chinY = -4;
pupilS = 1;
earS = 1; earY = 0; earRotL = "0deg"; earRotR = "0deg"; earringX = -4; earringY = -2;
tongueY = 0; toothTopY = 0; toothBotY = 0;
break;
case 4:
eyeTarg = eye4;
mouthTarg = mouth4;
chinY = 3;
pupilS = 1.1;
earS = .95; earY = -3; earRotL = "2deg"; earRotR = "-2deg"; earringX = -2; earringY = -5;
tongueY = -4; toothTopY = 6; toothBotY = -16;
break;
case 5:
eyeTarg = eye5;
mouthTarg = mouth5;
chinY = 14;
pupilS = 1.2;
earS = .9; earY = -6; earRotL = "4deg"; earRotR = "-4deg"; earringX = 0; earringY = -10;
tongueY = 0; toothTopY = 2; toothBotY = -2;
break;
default:
break;
}
tl
.to(eyePaths, {morphSVG: eyeTarg}, 0)
.to(mouthPaths, {morphSVG: mouthTarg}, 0)
.to(chin, {y: chinY}, 0)
.to(pupil, {scale: pupilS}, 0)
.to(earL, {scale: earS, y: earY, rotate: earRotL}, 0)
.to(earR, {scale: earS, y: earY, rotate: earRotR}, 0)
.to(earring, {x: earringX, y: earringY}, 0)
.to(tongue, {y: tongueY}, 0)
.to(toothTop, {y: toothTopY}, 0)
.to(toothBot, {y: toothBotY}, 0)
;
if(hornsU.length) {
if(dur) {
gsap.to(hornsU, {scale: 1, stagger:{each:.1, ease: "power1.out"}, duration: dur, ease: "back.out"});
} else {
gsap.set(hornsU, {scale: 1});
}
}
if(hornsD.length) {
if(dur) {
gsap.to(hornsD, {scale: 0, stagger: {each:-.08, ease: "power2.out"}, duration: dur, ease: "back.in"});
} else {
gsap.set(hornsD, {scale: 0});
}
}
curRating = num;
tl.play();
}
function onReduceMotionMQ() {
// change animation time depending on user preference
if(mq.matches) {
dur = durReduced;
} else {
dur = durNoPref;
}
}