2 845 Codepen

Звёздный рейтинг

Звездный рейтинг с 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;
    }
}

Комментарии

  • Facebook
  • Вконтакте

Похожие статьи