Syncope.T-*
728x90

눈알하면 미니언 밖에 생각이 안난다. 그래서 미니언을 예제로 구현해보았다.

 

에셋은 첨부합니다.

assets.zip
2.56MB

 

[HTML]

<template>
    <div class="body">
        <div class="eyes">
            <div class="eye">
                <div class="ball">

                </div>
            </div>
            <div class="eye">
                <div class="ball">

                </div>
            </div>
        </div>
    </div>
</template>

[CSS]

<style>
    *{
        padding: 0;
    }
    body{
        display: flex;
        justify-content: center;
        align-items: center;
    }
    .body{
        background: #fff url('../assets/minion.png');
        background-repeat: no-repeat;
        background-size: cover;
        width: 348px;
        height: 553.7px;
        margin-top:90px;

    }
    .eyes{
        display: flex;
        justify-content: center;
        align-items: center;
        margin-top: 105px;
    }
    .eye{
        width: 89.7px;
        height: 78px;
        border-radius: 50%;
        float: left;
        margin: 12px;
    }
    .ball{
        background: url('../assets/minion-eye.png');
        background-repeat: no-repeat;
        background-size: cover;
        width: 42.3px;
        height: 42.3px;
        border-radius: 50%;
        margin-top: 105px;
    }
</style>

[Javascript - Vanila]

var ball = document.getElementsByClassName('ball');
document.onmousemove = function () {
	var x = event.clientX * 100 / window.innerWidth + '%';
	var y = event.clientY * 100 / window.innerHeight + '%';

	for(var i = 0; i < 2; i++){
		ball[i].style.left = x / 2;
		ball[i].style.top = y / 2;
		ball[i].style.transform = 'translate(' + x + ', ' + y + ')';
	}
};

[Working - Mouse Tracking]

 

 

Element 좌표를 제대로 구할 수만 있다면 커서위치도 따라가게끔 할수 있지않을까 하여 아래처럼 Input을 넣고 눈알을 굴리게 해보았다.

 

[HTML]

<template>
    <div>
        <div class="body">
            <div class="eyes">
                <div class="eye">
                    <div class="ball">

                    </div>
                </div>
                <div class="eye">
                    <div class="ball">

                    </div>
                </div>
            </div>
        </div>
        <div class="row">
            <span>
                <input class="swing" id="search" type="text" placeholder="검색할 내용 입력" maxlength="50"/><label for="search">검색</label>
            </span>
        </div>
    </div>
</template>

[CSS]

<style>
    * {
        padding: 0;
        box-sizing: border-box;
    }

    body {
        display: flex;
        justify-content: center;
        align-items: center;
        overflow-x: hidden;
        font-weight: 300;
        color: #fff;
        background: #efefef;
    }

    .body {
        background: #fff url('../assets/minion.png');
        background-repeat: no-repeat;
        background-position: center center;
        background-size: contain;
        -webkit-background-size: contain;
        -moz-background-size: contain;
        -o-background-size: contain;
        width: 348px;
        height: 553.7px;
        margin-top: 90px;

    }

    .eyes {
        display: flex;
        justify-content: center;
        align-items: center;
        margin-top: 105px;
    }

    .eye {
        width: 89.7px;
        height: 78px;
        border-radius: 50%;
        float: left;
        margin: 12px;
    }

    .ball {
        background: url('../assets/minion-eye.png');
        background-repeat: no-repeat;
        background-size: cover;
        width: 42.3px;
        height: 42.3px;
        border-radius: 50%;
        margin-top: 105px;
    }

    .row {
        max-width: 800px;
        margin: 0 auto;
        padding: 60px 30px;
        background: #032429;
        position: relative;
        z-index: 1;
        text-align: center;
    }

    .row span {
        position: relative;
        display: inline-block;
        margin: 30px 10px;
    }

    input {
        font-size: 100%;
        line-height: 1.15;
        margin: 0;
    }

    .swing {
        display: inline-block;
        width: 555px;
        padding: 10px 0 10px 15px;
        font-weight: 400;
        color: #377D6A;
        background: #efefef;
        border: 0;
        border-radius: 3px;
        outline: 0;
        text-indent: 60px;
        transition: all .3s ease-in-out;
    }

    .swing::-webkit-input-placeholder {
        color: #efefef;
        text-indent: 0;
        font-weight: 300;
    }

    .swing + label {
        display: inline-block;
        position: absolute;
        top: 0;
        left: 0;
        padding: 10px 15px;
        text-shadow: 0 1px 0 rgba(19, 74, 70, 0.4);
        background: #7AB893;
        border-top-left-radius: 3px;
        border-bottom-left-radius: 3px;
        transform-origin: 2px 2px;
        transform: rotate(0);
        animation: swing-back .4s 1 ease-in-out;
    }

    @keyframes swing {
        0% {
            transform: rotate(0);
        }
        20% {
            transform: rotate(116deg);
        }
        40% {
            transform: rotate(60deg);
        }
        60% {
            transform: rotate(98deg);
        }
        80% {
            transform: rotate(76deg);
        }
        100% {
            transform: rotate(82deg);
        }
    }

    @keyframes swing-back {
        0% {
            transform: rotate(82deg);
        }
        100% {
            transform: rotate(0);
        }
    }

    .swing:focus,
    .swing:active {
        color: #377D6A;
        text-indent: 0;
        background: #fff;
        border-top-left-radius: 0;
        border-bottom-left-radius: 0;
    }

    .swing:focus::-webkit-input-placeholder,
    .swing:active::-webkit-input-placeholder {
        color: #aaa;
    }

    .swing:focus + label,
    .swing:active + label {
        animation: swing 1.4s 1 ease-in-out;
        transform: rotate(82deg);
    }
</style>

[Javascript]

            var ball = document.getElementsByClassName('ball');
            var input = document.getElementById('search');
            input.onkeydown = function () {
                var coords = getCoords(input);
                var x = coords.x * 100 / window.innerWidth + '%';
                var y = (coords.y * 100 / window.innerHeight) + 20 + '%';

                console.log(x, y);
                for (var i = 0; i < 2; i++) {
                    ball[i].style.left = x / 2;
                    ball[i].style.top = y / 2;
                    ball[i].style.transform = 'translate(' + x + ', ' + y + ')';
                }
            };

            var properties = [
                'direction',
                'boxSizing',
                'width',
                'height',
                'overflowX',
                'overflowY',

                'borderTopWidth',
                'borderRightWidth',
                'borderBottomWidth',
                'borderLeftWidth',
                'borderStyle',

                'paddingTop',
                'paddingRight',
                'paddingBottom',
                'paddingLeft',

                // https://developer.mozilla.org/en-US/docs/Web/CSS/font
                'fontStyle',
                'fontVariant',
                'fontWeight',
                'fontStretch',
                'fontSize',
                'fontSizeAdjust',
                'lineHeight',
                'fontFamily',

                'textAlign',
                'textTransform',
                'textIndent',
                'textDecoration',

                'letterSpacing',
                'wordSpacing',

                'tabSize',
                'MozTabSize'

            ];

            var isBrowser = (typeof window !== 'undefined');
            var isFirefox = (isBrowser && window.mozInnerScreenX != null);

            function getCoords(target) {
                var coordinates = getCaretCoordinates(target, target.selectionStart);
                var elementCoordinates = getElementCoords(target);
                var topPosition = coordinates.top + elementCoordinates.top;
                var leftPosition = coordinates.left + elementCoordinates.left;
                return {
                    x: leftPosition,
                    y: topPosition
                }
            }

            function getCaretCoordinates(element, position, options) {
                if (!isBrowser) {
                    throw new Error('브라우저 지원안함');
                }

                var debug = options && options.debug || false;
                if (debug) {
                    var el = document.querySelector('#search');
                    if (el) {
                        el.parentNode.removeChild(el);
                    }
                }

                var div = document.createElement('div');
                div.id = 'search';
                document.body.appendChild(div);

                var style = div.style;
                var computed = window.getComputedStyle ? getComputedStyle(element) : element.currentStyle;

                style.whiteSpace = 'pre-wrap';
                if (element.nodeName !== 'INPUT')
                    style.wordWrap = 'break-word';

                style.position = 'absolute';
                if (!debug)
                    style.visibility = 'hidden';

                properties.forEach(function (prop) {
                    style[prop] = computed[prop];
                });

                if (isFirefox) {
                    if (element.scrollHeight > parseInt(computed.height))
                        style.overflowY = 'scroll';
                } else {
                    style.overflow = 'hidden';
                }

                div.textContent = element.value.substring(0, position);
                if (element.nodeName === 'INPUT')
                    div.textContent = div.textContent.replace(/\s/g, '\u00a0');

                var span = document.createElement('span');
                span.textContent = element.value.substring(position) || '.';
                div.appendChild(span);

                var coordinates = {
                    top: span.offsetTop + parseInt(computed['borderTopWidth']),
                    left: span.offsetLeft + parseInt(computed['borderLeftWidth'])
                };

                if (debug) {
                    span.style.backgroundColor = '#aaa';
                } else {
                    document.body.removeChild(div);
                }

                return coordinates;
            }

            function getElementCoords(elem) {
                var box = elem.getBoundingClientRect();

                var body = document.body;
                var docEl = document.documentElement;

                var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
                var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;

                var clientTop = docEl.clientTop || body.clientTop || 0;
                var clientLeft = docEl.clientLeft || body.clientLeft || 0;

                var top = box.top + scrollTop - clientTop;
                var left = box.left + scrollLeft - clientLeft;

                return {top: Math.round(top), left: Math.round(left)};
            }

 

[Working - Input Caret Tracking]

 

Note. 이쁘게 꾸민다면, 지니 요정 사이트 처럼 이미지도 그럴싸 하게 쓰면 좋을것 같긴 하다.

추가로, Javascript로 Caret의 위치를 구하는것 보다는,

MaxLength를 두고, 반응형 프레임워크에서 Jquery로 간단하게 Input Length와 Width값 비율로 X위치를 구하는게 더 좋을수 있다.

profile

Syncope.T-*

@Syncope

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

profile on loading

Loading...