[jQuery] TextBox에서 다중 선택 기능 제작[jQuery] TextBox에서 다중 선택 기능 제작

Posted at 2020. 7. 24. 07:54 | Posted in JavaScript & jQuery/jQuery





■ 텍스트 입력박스 다중 선택 기능 만들기






jQuery UI 중에는 다중 선택을 위한 Autocomplete - Multiple values 기능이 존재한다.


여러개의 항목중 원하는 몇가지를 선택하는것에 적합한데.


샘플코드( https://jqueryui.com/autocomplete/#multiple ) 를 보면 쉽게 알 수 있을 것이다.


그렇지만 위 샘플코드에서는 선택 입력한 값의 내용이 다시 선택이 가능하다는 단점이 존재하여.


한번 선택한 항목은 선택에서 배제될 수 있게 내용을 조금 수정해 보았다.




# 소스코드

<html lang="ko">

<head>

<meta charset="utf-8">

<title>jQuery UI Autocomplete - 다중 선택</title>

<link rel="stylesheet" href="http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">

<script src="http://code.jquery.com/jquery-1.12.4.js"></script>

<script src="http://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

<script type="text/javascript">

    jQuery(document).ready(function() {


        jQuery( "#tags" ).on( "keydown" , function( event ) {


            // 항목을 선택할때 탭으로 이동하지 못하게 한다.

            if( event.keyCode === jQuery.ui.keyCode.TAB && jQuery(this).autocomplete("instance").menu.active ) {

                event.preventDefault();

            }


        }).autocomplete({

              minLength : 0

            , source : function( request, response ) {


                // Autocomplete 자동완성 문자 리스트 - 초기값 ( 변경되지 않는 절대값 )

                const availableTags = [

                      "파이어폭스", "크롬", "오페라", "웨일", "사파리", "익스플로러", "엣지"

                    , "비발디", "브레이브", "돌핀", "토치", "미도리", "아반트", "맥스톤"

                ];


                // Autocomplete 자동완성 문자 리스트 - 변경값 ( 검색이 이루어지는 실제 배열의 삭제 및 재생산이 이루어짐 )

                let unfoldTags = availableTags;


                // 콤마( , )로 구분되는 문자열을 배열로 만든다.

                let arrTrem = request.term.split(",");


                // 문자 리스트에서 이미 선택된 문자열은 삭제한다.

                arrTrem.forEach(function(trem) {


                    let search = unfoldTags.indexOf( trem.trim() );


                    if(search != -1) {

                        unfoldTags.splice(search, 1);

                    }

                });


                // 자동 완성을 다시 실행하지만, 마지막 용어를 추출한다.

                response(jQuery.ui.autocomplete.filter(unfoldTags, extractLast(request.term)));

                unfoldTags = null;

            }

            , focus : function() {

                return false;

            }

            , select : function(event, ui) {


                let terms = split(this.value);


                // 현재 입력값을 제거한다.

                terms.pop();


                // 선택된 아이템을 추가한다.

                terms.push(ui.item.value);


                // 끝에 콤마와 공백을 추가한다.

                terms.push("");

                this.value = terms.join(", ");


                return false;

            }

        });


        // 공백문자에 대응

        function split(val) {

            return val.split( /,\s*/ );

        }


        // 배열의 마지막 요소를 제거한 후, 제거한 요소를 반환

        function extractLast(term) {

            return split(term).pop();

        }

    });

</script>

</head>

<body>

<div class="ui-widget">

    <label for="tags">프로그래밍 언어 : </label>

    <input id="tags" size="80" value="">

</div>

</body>

</html>






# 출력결과











Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] 자바스크립트를 이용한 캘린더 제작[JavaScript] 자바스크립트를 이용한 캘린더 제작

Posted at 2020. 7. 13. 09:28 | Posted in JavaScript & jQuery/JavaScript




참고 : https://jerryjerryjerry.tistory.com/26






■ 순수 자바스크립트만을 이용한 달력 제작





jQuery등을 통한 캘린더 라이브러리가 많이 존재하지만 뭔가 꼭 있어야 하거나, 구현해야하는 효과가 있는경우


원하는 캘린더 라이브러리를 다시 찾아봐야 하거나, 라이브러리를 마개조 해야하는 상황이 발생하여


순수하게 자바스크립트만을 이용한 달력을 제작하게 되었다.








위 세가지 조건을 만족시키는 캘린더를 제작해 보려고 한다.






# 소스코드

<html>
<head>
<title>:: JavaScript 캘린더 ::</title>
<style type="text/css">
    a { color:#000000;text-decoration:none; }
    .scriptCalendar { text-align:center; }
    .scriptCalendar > thead > tr > td { width:50px;height:50px; }
    .scriptCalendar > thead > tr:first-child > td { font-weight:bold; }
    .scriptCalendar > thead > tr:last-child > td { background-color:#90EE90; }
    .scriptCalendar > tbody > tr > td { width:50px;height:50px; }
</style>
<script type="text/javascript">
    document.addEventListener("DOMContentLoaded", function() {
        buildCalendar();
    });

    var today = new Date(); // @param 전역 변수, 오늘 날짜 / 내 컴퓨터 로컬을 기준으로 today에 Date 객체를 넣어줌
    var date = new Date();  // @param 전역 변수, today의 Date를 세어주는 역할

    /**
     * @brief   이전달 버튼 클릭
     */
    function prevCalendar() {
        this.today = new Date(today.getFullYear(), today.getMonth() - 1, today.getDate());
        buildCalendar();    // @param 전월 캘린더 출력 요청
    }

    /**
     * @brief   다음달 버튼 클릭
     */
    function nextCalendar() {
        this.today = new Date(today.getFullYear(), today.getMonth() + 1, today.getDate());
        buildCalendar();    // @param 명월 캘린더 출력 요청
    }

    /**
     * @brief   캘린더 오픈
     * @details 날짜 값을 받아 캘린더 폼을 생성하고, 날짜값을 채워넣는다.
     */
    function buildCalendar() {

        let doMonth = new Date(today.getFullYear(), today.getMonth(), 1);
        let lastDate = new Date(today.getFullYear(), today.getMonth() + 1, 0);

        let tbCalendar = document.querySelector(".scriptCalendar > tbody");


        document.getElementById("calYear").innerText = today.getFullYear();                                  // @param YYYY월
        document.getElementById("calMonth").innerText = autoLeftPad((today.getMonth() + 1), 2);   // @param MM월

        // @details 이전 캘린더의 출력결과가 남아있다면, 이전 캘린더를 삭제한다.
        while(tbCalendar.rows.length > 0) {
            tbCalendar.deleteRow(tbCalendar.rows.length - 1);
        }


        // @param 첫번째 개행
        let row = tbCalendar.insertRow();


        // @param 날짜가 표기될 열의 증가값
        let dom = 1;

        // @details 시작일의 요일값( doMonth.getDay() ) + 해당월의 전체일( lastDate.getDate())을  더해준 값에서
        //               7로 나눈값을 올림( Math.ceil() )하고 다시 시작일의 요일값( doMonth.getDay() )을 빼준다.
        let daysLength = (Math.ceil((doMonth.getDay() + lastDate.getDate()) / 7) * 7) - doMonth.getDay();

        // @param 달력 출력

        // @details 시작값은 1일을 직접 지정하고 요일값( doMonth.getDay() )를 빼서 마이너스( - )로 for문을 시작한다.
        for(let day = 1 - doMonth.getDay(); daysLength >= day; day++) {

            let column = row.insertCell();

            // @param 평일( 전월일과 익월일의 데이터 제외 )
            if(Math.sign(day) == 1 && lastDate.getDate() >= day) {


                // @param 평일 날짜 데이터 삽입

                column.innerText = autoLeftPad(day, 2);


                // @param 일요일인 경우
                if(dom % 7 == 1) {
                    column.style.color = "#FF4D4D";
                }

                // @param 토요일인 경우
                if(dom % 7 == 0) {
                    column.style.color = "#4D4DFF";
                    row = tbCalendar.insertRow();   // @param 토요일이 지나면 다시 가로 행을 한줄 추가한다.
                }

            }

            // @param 평일 전월일과 익월일의 데이터 날짜변경
            else {
                let exceptDay = new Date(doMonth.getFullYear(), doMonth.getMonth(), day);
                column.innerText = autoLeftPad(exceptDay.getDate(), 2);
                column.style.color = "#A9A9A9";
            }

            // @brief   전월, 명월 음영처리
            // @details 현재년과 선택 년도가 같은경우
            if(today.getFullYear() == date.getFullYear()) {

                // @details 현재월과 선택월이 같은경우
                if(today.getMonth() == date.getMonth()) {

                    // @details 현재일보다 이전인 경우이면서 현재월에 포함되는 일인경우
                    if(date.getDate() > day && Math.sign(day) == 1) {
                        column.style.backgroundColor = "#E5E5E5";
                    }

                    // @details 현재일보다 이후이면서 현재월에 포함되는 일인경우
                    else if(date.getDate() < day && lastDate.getDate() >= day) {
                        column.style.backgroundColor = "#FFFFFF";
                        column.style.cursor = "pointer";
                        column.onclick = function(){ calendarChoiceDay(this); }
                    }

                    // @details 현재일인 경우
                    else if(date.getDate() == day) {
                        column.style.backgroundColor = "#FFFFE6";
                        column.style.cursor = "pointer";
                        column.onclick = function(){ calendarChoiceDay(this); }
                    }

                // @details 현재월보다 이전인경우
                } else if(today.getMonth() < date.getMonth()) {
                    if(Math.sign(day) == 1 && day <= lastDate.getDate()) {
                        column.style.backgroundColor = "#E5E5E5";
                    }
                }

                // @details 현재월보다 이후인경우
                else {
                    if(Math.sign(day) == 1 && day <= lastDate.getDate()) {
                        column.style.backgroundColor = "#FFFFFF";
                        column.style.cursor = "pointer";
                        column.onclick = function(){ calendarChoiceDay(this); }
                    }
                }
            }

            // @details 선택한년도가 현재년도보다 작은경우
            else if(today.getFullYear() < date.getFullYear()) {
                if(Math.sign(day) == 1 && day <= lastDate.getDate()) {
                    column.style.backgroundColor = "#E5E5E5";
                }
            }

            // @details 선택한년도가 현재년도보다 큰경우
            else {
                if(Math.sign(day) == 1 && day <= lastDate.getDate()) {
                    column.style.backgroundColor = "#FFFFFF";
                    column.style.cursor = "pointer";
                    column.onclick = function(){ calendarChoiceDay(this); }
                }
            }


            dom++;

        }
    }

    /**
     * @brief   날짜 선택
     * @details 사용자가 선택한 날짜에 체크표시를 남긴다.
     */
    function calendarChoiceDay(column) {

        // @param 기존 선택일이 존재하는 경우 기존 선택일의 표시형식을 초기화 한다.
        if(document.getElementsByClassName("choiceDay")[0]) {
            document.getElementsByClassName("choiceDay")[0].style.backgroundColor = "#FFFFFF";
            document.getElementsByClassName("choiceDay")[0].classList.remove("choiceDay");
        }

        // @param 선택일 체크 표시
        column.style.backgroundColor = "#FF9999";


        // @param 선택일 클래스명 변경

        column.classList.add("choiceDay");
    }

    /**
     * @brief   숫자 두자릿수( 00 ) 변경
     * @details 자릿수가 한지라인 ( 1, 2, 3등 )의 값을 10, 11, 12등과 같은 두자리수 형식으로 맞추기위해 0을 붙인다.
     * @param   num     앞에 0을 붙일 숫자 값
     * @param   digit   글자의 자릿수를 지정 ( 2자릿수인 경우 00, 3자릿수인 경우 000 … )
     */
    function autoLeftPad(num, digit) {
        if(String(num).length < digit) {
            num = new Array(digit - String(num).length + 1).join("0") + num;
        }
        return num;

    }

</script>
</head>
<body>
<table class="scriptCalendar">
    <thead>
        <tr>
            <td onClick="prevCalendar();" style="cursor:pointer;">&#60;&#60;</td>
            <td colspan="5">
                <span id="calYear">YYYY</span>년
                <span id="calMonth">MM</span>월
            </td>
            <td onClick="nextCalendar();" style="cursor:pointer;">&#62;&#62;</td>
        </tr>
        <tr>
            <td>일</td><td>월</td><td>화</td><td>수</td><td>목</td><td>금</td><td>토</td>
        </tr>
    </thead>
    <tbody></tbody>
</table>
</body>
</html>





위 코드를 실행해 보면 결과가 아래와 같음을 확인 해 볼 수 있다.





# 출력결과
<< YYYY MM

>>


   좌측 캘린더를 클릭, 조작해보면.


   금일 날짜인 YYYYMMDD일 보다


   전일인 경우는 선택을 할 수 없게 처리 되어 있다.


   선택이 가능한 날은  단 하루 로 제한되어 있는 형태로


   위에서 표기한 필 수 구성 요소를 추가해둔 구성이다.







캘린더 라이브러리가 많이 지원되는 상황이지만.


역시 막상 내가 필요로 하는것을 구현하는것은 또 답답한 감이 있기에.


좀 공들여 포스팅을 정리하게 되었다.










  1. 럴커를 좋아하는 덱스~~~
    저 타입스크립트 시작 하는데
    자주 들려서 자바스크립트 도움 받을게요~~ㅎ
    아하하하하하~~
  2. 유선재
    자바스크립트 배우는과정중 한 화면에 달력2개만들기 과제하는데
    1개는 그대로 가져와서 써보고 2개째에 직접 뜯어서 해볼려니 하나도 모르겠네요 ㅠㅠ
    어떤 부분을 고쳐야 달력 2개생성이 가능할까요?

Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] SelectBox를 사용하는 날짜 검색창 제작[JavaScript] SelectBox를 사용하는 날짜 검색창 제작

Posted at 2020. 7. 12. 20:31 | Posted in JavaScript & jQuery/JavaScript







■ 셀렉트 박스를 이용한 캘린더 제작







위와 같이 <SELECT> 태그를 통해 날짜값을 지정하여 검색하는 페이지를 제작하게 되었다.


jQuery UI의 DatePicker등을 사용하면 그냥 손쉽게 해결 할 수 있고,


보통은 다 이렇게 하지만, 또 막상 일을 하다보면 위와 같은 검색을 선호하는 클라이언트가 또 있을 수 있다라는 생각이들어


추가적으로 실제 업무에서 많이 쓰이게 되는 GET 방식을 통한 검색조건 전달의 경우를 포함하여


내용을 정리해보았다.





※ 예외 처리해야할 사항들


 ① 매월의 마지막 날의 날짜는 항상 일치하지 않기에, 그달의 마지막 날보다 큰 날짜는 자동적으로 선택할 수 없어야 한다.

 ② 처음 접속시 해당월의 첫째날( 01일 )과 마지막날( 28일, 29,일 30일, 31일 등 )이 자동 세팅되어야 한다.

 ③ GET방식을 통해 검색 시작일과 종료일의 날짜 데이터가 전달되는 경우의 수를 처리해야 한다.

 ④ 사용자가 날짜를 선택하는 과정에서 31일이 선택되어 있는 가운데 31일이 존재하지 않는 년, 월을 선택한 경우

     해당 월의 마지막 날로 자동 변경시켜주어야 한다.




위 경우를 상정하여 아래 코드를 작성하게 되었다.




# 소스코드

<html>

<head>

<title>:: JavaScript 매월 주차 구하기 ::</title>

<script type="text/javascript">


    document.addEventListener("DOMContentLoaded", function() {


        const stdDays = document.querySelector("span:nth-child(1)");     // @param 시작일 영역지정

        const endDays = document.querySelector("span:nth-child(2)");    // @param 종료일 영역지정


        let stdFirstDate = null;    // @param 시작일의 첫날

        let endFirstDate = null;   // @param 종료일의 첫날

        let stdLastDate = null;    // @param 시작일의 전체일수

        let endLastDate = null;   // @param 종료일의 전체일수



        // @param GET방식으로 전달된 시작일, 종료일의 지정값이 존재하지 않는경우 ( ※ 맨처음 시작시에 실행 )

        if(nullPointerException(getParameter("stdDate")) == false && nullPointerException(getParameter("endDate")) == false) {


            const toDate = new Date();


            stdFirstDate = new Date(toDate.getFullYear(), (toDate.getMonth() + 1));

            stdLastDate = new Date(stdFirstDate.getFullYear(), (stdFirstDate.getMonth() + 1), 1);  // @param 다음달의 첫째날을 지정

            stdLastDate.setDate(0);    // @param 다음달에서 하루를 빼서 원하는 월의 마지막 날로 맞춤


            endFirstDate = new Date(toDate.getFullYear(), (toDate.getMonth() + 1));

            endLastDate = new Date(endFirstDate.getFullYear(), (endFirstDate.getMonth() + 1), 1);  // @param 다음달의 첫째날을 지정

            endLastDate.setDate(0);    // @param 다음달에서 하루를 빼서 원하는 월의 마지막 날로 맞춤


        }


        // @param GET방식으로 전달된 시작일, 종료일의 지정값이 존재하는 경우

        else {


            const stdDate = getParameter("stdDate");

            stdFirstDate = new Date(

                  Number(stdDate.substring(0, 4))

                , Number(stdDate.substring(6, 8))

                , Number(stdDate.substring(4, 6))

            );

            stdLastDate = new Date(stdFirstDate.getFullYear(), stdFirstDate.getMonth(), 1);  // @param 다음달의 첫째날을 지정

            stdLastDate.setDate(0);    // @param 다음달에서 하루를 빼서 원하는 월의 마지막 날로 맞춤


            const endDate = getParameter("endDate");

            endFirstDate = new Date(

                  Number(endDate.substring(0, 4))

                , Number(endDate.substring(4, 6))

                , Number(endDate.substring(6, 8))

            );

            endLastDate = new Date(endFirstDate.getFullYear(), endFirstDate.getMonth(), 1);  // @param 다음달의 첫째날을 지정

            endLastDate.setDate(0);    // @param 다음달에서 하루를 빼서 원하는 월의 마지막 날로 맞춤


        }


        // @param 년도( Year ) - 선택

        for(let year = 0; stdDays.querySelector("select:nth-child(1)").length > year; year++) {

            if(stdDays.querySelector("select:nth-child(1)").options[year].value == stdFirstDate.getFullYear()) {

                stdDays.querySelector("select:nth-child(1)").options[year].selected = true;

            }


            if(endDays.querySelector("select:nth-child(1)").options[year].value == stdFirstDate.getFullYear()) {

                endDays.querySelector("select:nth-child(1)").options[year].selected = true;

            }

        }


        // @param 월( Month ) - 선택

        for(let month = 0; stdDays.querySelector("select:nth-child(2)").length > month; month++) {

            if(stdDays.querySelector("select:nth-child(2)").options[month].value == stdFirstDate.getMonth()) {

                stdDays.querySelector("select:nth-child(2)").options[month].selected = true;

            }


            if(endDays.querySelector("select:nth-child(2)").options[month].value == endFirstDate.getMonth()) {

                endDays.querySelector("select:nth-child(2)").options[month].selected = true;

            }

        }


        // @param 일( Day ) - 생성 및 선택

        // @details - 날짜는 매월 마지막일이 다르게 끝나기 때문에 직접 생성하고,

        //                선택한 날( 기본값 시작일 - 01일, 종료일은 - 말일 )을 자동으로 selected 한다.

        for(let date = 1; stdLastDate.getDate() >= date; date++) {

            if(stdFirstDate.getDate() == date) {

                stdDays.querySelector("select:nth-child(3)").innerHTML

                    += "<option value='" + date + "' selected>" + autoLeftPad(date, 2) + "</option>";

            } else {

                stdDays.querySelector("select:nth-child(3)").innerHTML

                    += "<option value='" + date + "'>" + autoLeftPad(date, 2) + "</option>";

            }

        }


        for(let date = 1; endLastDate.getDate() >= date; date++) {

            if((nullPointerException(getParameter("endDate")) == true) ? endFirstDate.getDate() : endLastDate.getDate() == date) {

                endDays.querySelector("select:nth-child(3)").innerHTML

                    += "<option value='" + date + "' selected>" + autoLeftPad(date, 2) + "</option>";

            } else {

                endDays.querySelector("select:nth-child(3)").innerHTML

                    += "<option value='" + date + "'>" + autoLeftPad(date, 2) + "</option>";

            }

        }

    });



    /**

     * @brief   시작일( 년, 월 ), 종료일 ( 년, 월 )의 값이 변경된 경우 실행

     * @details 시작일( 년, 월 ), 종료일 ( 년, 월 )의 값이 변경에 따른 해당 년월의 전체일수를 다시 체크,

     *             변경된 년월의 일보다 선택된 일이 큰경우 마지막 날로 선택일 자동 변경

     */

    function changeConditionPeriod(cal) {


        const searchDays = cal.parentNode;

        const checkDate = searchDays.querySelector("select:nth-child(3)").value;


        // @param 다음달의 첫째날을 지정

        let lastDate = new Date(

              searchDays.querySelector("select:nth-child(1)").value

            , searchDays.querySelector("select:nth-child(2)").value

            , 1

        );

        lastDate.setDate(0);    // @param 하루를 뺌


        // @param 일정보 초기화

        searchDays.querySelector("select:nth-child(3)").innerHTML = "";


        // @param 일정보 재삽입

        for(let date = 1; lastDate.getDate() >= date; date++) {

            if(checkDate == date) {

                searchDays.querySelector("select:nth-child(3)").innerHTML

                    += "<option value='" + date + "' selected>" + autoLeftPad(date, 2) + "</option>";

            } else {

                searchDays.querySelector("select:nth-child(3)").innerHTML

                    += "<option value='" + date + "'>" + autoLeftPad(date, 2) + "</option>";

            }

        }


        // @param 일정보 예외처리 선택되어있는 마지막 날이 바꾼 월의 날보다 큰경우의 예외처리

        if(checkDate > lastDate.getDate()) {

            searchDays.querySelector("select:nth-child(3) > option:last-child").selected = true;

        }

    }


    /**

     * @brief   강제로 앞에 0을 붙여서 두자릿수 숫자로 변경한다.

     * @param   num     앞에 0을 붙일 숫자 값

     * @param   digit   자릿수를 지정

     */

    function autoLeftPad(num, digit) {

        if(String(num).length < digit) { num = new Array(digit - String(num).length + 1).join("0") + num; }

        return num;

    }


    /**

     * @brief   GET으로 넘어오는 값의 존재 여부를 체크

     */

    function nullPointerException(worth) {

        if(

               worth == "" 

            || worth == null 

            || worth == undefined 

            || (worth != null && typeof worth == "object" && !Object.keys(worth).length == "")

        ) {

            return false;

        } else {

            return true;

        }

    }


    /**

     * @brief   GET방식으로 전달된 값을 추출

     * @param   param     추출할 key의 명칭

     */

    var getParameter = function(param) {

        let returnValue;

        let url = location.href;

        let parameters = (url.slice(url.indexOf("?") + 1, url.length)).split("&");

        for(let i = 0; i < parameters.length; i++) {

            let varName = parameters[i].split("=")[0];

            if (varName.toUpperCase() == param.toUpperCase()) {

                returnValue = parameters[i].split("=")[1];

                return decodeURIComponent(returnValue);

            }

        }

    };

</script>

</head>

<body>

    <h1>■ SelectBox를 이용한 캘린더</h1>

    <hr/>

    <!-- 년( Year )은 자동으로 생성시 너무 많이 늘어날 수 있어서 -->

    <!-- 월( Month )은 01 ~ 12라는 고정값을 알고 있기에 직접 값을 지정 -->

    <!-- 일( Day )은 마지막 일이 항상 변하기 때문에 자동 생성 한다. -->

    <div>

        <span>

            시작일&nbsp;:&nbsp;

            <select onChange="changeConditionPeriod(this);">

                <option value="2018">2018</option>

                <option value="2019">2019</option>

                <option value="2020">2020</option>

                <option value="2021">2021</option>

                <option value="2022">2022</option>

                <option value="2023">2023</option>

                <option value="2024">2024</option>

                <option value="2025">2025</option>

            </select>

            &nbsp;년&nbsp;&nbsp;

            <select onChange="changeConditionPeriod(this);">

                <option value="1">01</option>

                <option value="2">02</option>

                <option value="3">03</option>

                <option value="4">04</option>

                <option value="5">05</option>

                <option value="6">06</option>

                <option value="7">07</option>

                <option value="8">08</option>

                <option value="9">09</option>

                <option value="10">10</option>

                <option value="11">11</option>

                <option value="12">12</option>

            </select>

            &nbsp;월&nbsp;&nbsp;

            <select class="choiceDay"></select>

            &nbsp;일

        </span>

        &nbsp;&nbsp;~&nbsp;&nbsp;

        <span>

            종료일&nbsp;:&nbsp;

            <select onChange="changeConditionPeriod(this);">

                <option value="2018">2018</option>

                <option value="2019">2019</option>

                <option value="2020">2020</option>

                <option value="2021">2021</option>

                <option value="2022">2022</option>

                <option value="2023">2023</option>

                <option value="2024">2024</option>

                <option value="2025">2025</option>

            </select>

            &nbsp;년&nbsp;&nbsp;

            <select onChange="changeConditionPeriod(this);">

                <option value="1">01</option>

                <option value="2">02</option>

                <option value="3">03</option>

                <option value="4">04</option>

                <option value="5">05</option>

                <option value="6">06</option>

                <option value="7">07</option>

                <option value="8">08</option>

                <option value="9">09</option>

                <option value="10">10</option>

                <option value="11">11</option>

                <option value="12">12</option>

            </select>

            &nbsp;월&nbsp;&nbsp;

            <select class="choiceDay"></select>

            &nbsp;일

        </span>

    </div>

</body>

</html> 



이제 위 코드를 브라우저를 통해 실행시켜 보면




# 출력결과




위와 같이 예외처리해야할 사항들이 정상적으로 반영되어 기능하는 모습을 확인 할 수 있다.








Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] 매월의 월요일 기준, 주차 구하기[JavaScript] 매월의 월요일 기준, 주차 구하기

Posted at 2020. 6. 29. 18:14 | Posted in JavaScript & jQuery/JavaScript




참고 : https://blog.naver.com/z1004man/220936098651

참고 : https://matthew-jo.tistory.com/8





매월 월요일을 기준으로하는 주차 및 해당주차의 날짜 구하기


( 부제 : 일요일을 마지막으로 하는 주차 구하기 )




선택한 매월의 월요일을 기준으로하는 해당월의 주차수와 각 주차별 월요일, 일요일 날짜를 구하는 함수




통계 프로그램을 만들면서 JSP, PHP, Oracle, MySQL등 여러가지 개발 언어를 사용하여


매월의 주차를 구하는 프로그램을 구현해야 하는 일이 종종 발생 하였다.


그런데 저렇게 다양한 환경에서 매번 그 언어에 맞게 다시 조립 및 분해하는 과정이 생기는게 싫어서.


이번에 아예 한번 자바스크립트로 클라이언트 영역에서 넘겨줄 값을 미리 다 생성해서 넘겨주면


좀더 환경에 자유로울 수 있을 것 같아 순수 자바스크립트로 매월의 ( 월요일을 시작을 기준 )으로 함수를 만들어 정리해 보았다.





# 소스코드

<html>

<head>

<title>:: JavaScript 매월 주차 구하기 ::</title>

<script type="text/javascript">


    // 기준요일에 따른 주차구하는 함수.

    // 해당 주차 / 해당주차 시작날짜 / 해당주차 끝나는날짜를 리턴.

    function searchPeriodCalculation() {


        let cYear = document.getElementById("choiceYear").value;

        let cMonth = document.getElementById("choiceMonth").value.replace(/(^0+)/, "") - 1;


        // 날짜형으로 데이트 포맷

        let date = new Date(cYear, cMonth);


        // 월요일을 중심으로한 주차 구하기( JS기준 : 일요일 0 월요일 1 ~ 토요일 6 )

        let firstDay = new Date(date.getFullYear(), date.getMonth(), 1);

        let lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);


        let weekObj = null;

        let weekObjArray = new Array();

        let weekStand = 8;  // 월요일 고정

        let firstWeekEndDate = true;

        let thisMonthFirstWeek = firstDay.getDay();


        for(var num = 1; num <= 6; num++) {


            // 마지막월과 첫번째월이 다른경우 빠져나온다.

            if(lastDay.getMonth() != firstDay.getMonth()) {

                break;

            }


            weekObj = new Object();


            // 한주의 시작일은 월의 첫번째 월요일로 설정

            if(firstDay.getDay() <= 1) {


                // 한주의 시작일이 일요일이라면 날짜값을 하루 더해준다.

                if(firstDay.getDay() == 0) { firstDay.setDate(firstDay.getDate() + 1); }


                weekObj.weekStartDate =

                      firstDay.getFullYear().toString()

                    + "-"

                    + numberPad((firstDay.getMonth() + 1).toString(), 2)

                    + "-"

                    + numberPad(firstDay.getDate().toString() , 2);

            }


            if(weekStand > thisMonthFirstWeek) {

                if(firstWeekEndDate) {

                    if((weekStand - firstDay.getDay()) == 1) {

                        firstDay.setDate(firstDay.getDate() + (weekStand - firstDay.getDay()) - 1);

                    }

                    if((weekStand - firstDay.getDay()) > 1) {

                        firstDay.setDate(firstDay.getDate() + (weekStand - firstDay.getDay()) - 1)

                    }

                    firstWeekEndDate = false;

                } else {

                    firstDay.setDate(firstDay.getDate() + 6);

                }

            } else {

                firstDay.setDate(firstDay.getDate() + (6 - firstDay.getDay()) + weekStand);

            }


            // 월요일로 지정한 데이터가 존재하는 경우에만 마지막 일의 데이터를 담는다.

            if(typeof weekObj.weekStartDate !== "undefined") {


                weekObj.weekEndDate =

                      firstDay.getFullYear().toString()

                    + "-"

                    + numberPad((firstDay.getMonth() + 1).toString(), 2)

                    + "-"

                    + numberPad(firstDay.getDate().toString(), 2);

                    

                weekObjArray.push(weekObj);

            }


            firstDay.setDate(firstDay.getDate() + 1);

        }


        console.log( weekObjArray );

    }


    // 월, 일 날짜값 두자리( 00 )로 변경

    function numberPad(num, width) {

        num = String(num);

        return num.length >= width ? num : new Array(width - num.length + 1).join("0") + num;

    }

</script>

</head>

<body>

    <div>

        <input type="text" id="choiceYear" style="text-align:center;" value="2020"/>

        &nbsp;년&nbsp;&nbsp;

        <select id="choiceMonth">

            <option value="01">01</option>

            <option value="02">02</option>

            <option value="03">03</option>

            <option value="04">04</option>

            <option value="05">05</option>

            <option value="06">06</option>

            <option value="07">07</option>

            <option value="08">08</option>

            <option value="09">09</option>

            <option value="10">10</option>

            <option value="11">11</option>

            <option value="12">12</option>

        </select>

        &nbsp;월&nbsp;&nbsp;

        <button type="button" onClick="searchPeriodCalculation( );">검색</button>

    </div>

</body>

</html>




위 코드의 결과는 아래와 같다.



# 출력 결과















Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] Table을 Excel 처럼 즉시 수정가능하게 만들기[JavaScript] Table을 Excel 처럼 즉시 수정가능하게 만들기

Posted at 2020. 6. 24. 09:46 | Posted in JavaScript & jQuery/JavaScript




주의 : 해당 포스팅의 샘플 코드에서 사용하는 addEventListener( ) 메서드의 경우 Internet Explorer에서는 정상적으로 작동하지 않습니다.

           호환되지 않는 Internet Explorer에서의 사용의 경우는 addEventListener( ) 메서드를 attachEven( )로 변경하여 작업을 진행하셔야 합니다.






contenteditable 속성을 이용한 텍스트 내용 수정




기본적으로 웹 환경에서 값을 변경하기 위해서는 <input type="text" value="값">이 기본 형태였지만.


HTML5가 나오면서 contenteditable을 이용해 좀더 재미있는 사용자 경험을 제공할 수 있게 되었다.


해당 포스팅에서는 웹 페이지에 출력된 텍스트 문구를 contenteditable 속성을 이용하여 수정해 보려 한다.




# 소스코드

<html>
<head>
<title>:: JavaScript Contenteditable ::</title>
</head>
<body>
<p contenteditable="false">
    이 단락은 편집을 원하는 경우 더블 클릭해 주세요
</p>
</body>
</html>
<script type="text/javascript">

    // @breif contenteditable 속성을 가진경우
    content = document.querySelector( "[contenteditable]" );
   
    document.addEventListener("DOMContentLoaded", function() {

        // @breif 더블클릭시 실행
        content.addEventListener("dblclick", function(event) {

            // @details contenteditable 속성이 수정 불가인 경우 실행( false )
            if(content.isContentEditable == false) {

                // @details 편집 가능 상태로 변경
                content.contentEditable = true;

                // @details 텍스트 문구 변경
                content.textContent = "편집 가능한 상태로 변경되었습니다.";

                // @details CSS 효과 추가
                content.style.border = "1px solid #FE7F9C";

                // @details 포커스 지정
                content.focus();
            }

            // @details contenteditable 속성이 수정 가능인 경우 실행( true )
            else {

                // 편집 불가 상태로 변경
                content.contentEditable = false;
                content.style.border = "0px";
            }
        });
    });
</script>




# 출력결과












■ 테이블을 엑셀처럼 즉시 변경가능하게 만들기





이제 contenteditable 태그를 좀더 심도있게 활용을 해보자.


바로 테이블에 출력되어 있는 내용을 엑셀처럼 즉시 수정을 하고 해당내용을 적용하는 것이다.


즉각적으로 수정된 내용을 데이타 베이스( DataBase )에 적용하는 예제는 아니지만.


해당 내용의 결과물을 본다면 어떻게 사용하는것이 좋을지 바로 감이 올 거라 생각한다.



# 소스코드

<html>

<head>

<title>:: JavaScript Contenteditable ::</title>

<style type="text/css">

    table { border-collapse:collapse;border:1px gray solid; }

    .rowColumn { border-radius:5px;margin:5px; }

</style>

</head>

<body>

<table border="1">

    <thead>

        <tr>

            <th style="width:50px;">번호</th>

            <th style="width:120px;">가수</th>

            <th style="width:350px;">노래</th>

            <th style="width:100px;">발매일</th>

        </tr>

    </thead>

    <tbody>

        <tr>

            <td style="text-align:center;">1</td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="윤하">윤하</p>

            </td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="오렌지 첫사랑">오렌지 첫사랑</p>

            </td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="2007-10-23">2007-10-23</p>

            </td>

        </tr>

        <tr>

            <td style="text-align:center;">2</td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="도원경">도원경</p>

            </td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="다시 사랑한다면">다시 사랑한다면</p>

            </td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="2001-05-01">2001-05-01</p>

            </td>

        </tr>

        <tr>

            <td style="text-align:center;">3</td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="더더">더더</p>

            </td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="it's You">it's You</p>

            </td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="1998-11-01">1998-11-01</p>

            </td>

        </tr>

        <tr>

            <td style="text-align:center;">4</td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="박기영">박기영</p>

            </td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="시작">시작</p>

            </td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="1999-04-07">1999-04-07</p>

            </td>

        </tr>

        <tr>

            <td style="text-align:center;">5</td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="이소은">이소은</p>

            </td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="오래오래">오래오래</p>

            </td>

            <td>

                <p class="rowColumn" contenteditable="false" data-default="2002-12-21">2002-12-21</p>

            </td>

        </tr>

    </tboyd>

</talbe>

</body>

</html>

<script type="text/javascript">


    // @breif contenteditable 속성을 가진경우

    contents = document.getElementsByClassName("rowColumn");


    document.addEventListener("DOMContentLoaded", function() {


        // @breif rowColumn 클래스의 갯수 만큼 반복문을 실행한다.

        Array.from(contents).forEach(function(content) {


            // @breif 마우스로 해당영역을 더블클릭 한경우

            content.addEventListener("dblclick", function(event) {


                // @breif 전체 테이블 컬럼( td > p )에서 현재 사용중인 값의 존재여부를 확인한다.

                Array.from(contents).forEach(function(defaultVal) {


                    /*
                    // @details 빈값( null )이 존재하는지 체크한다.
                    if(
                           defaultVal.textContent == ""
                        || defaultVal.textContent == null
                        || defaultVal.textContent == undefined
                        || (defaultVal.textContent != null
                        && typeof defaultVal.textContent == "object"
                        && !Object.keys(defaultVal.textContent).length == ""))
                    {

                        // @details 내용이 존재하지 않다면 data 태그의 기본값으로 되돌린다.
                        defaultVal.textContent = defaultVal.dataset.default;
                    }
                    */

                    // @details 저장하지 않은 내용이라고 판단하여 data 태그의 기본값으로 되돌린다.
                    defaultVal.textContent = defaultVal.dataset.default;

                    // @breif 수정 불가 상태로 되돌린다.

                    defaultVal.contentEditable = false;

                    defaultVal.style.border = "0px";

                });


                if(content.isContentEditable == false) {


                    // @details 편집 가능 상태로 변경

                    content.contentEditable = true;


                    // @details 텍스트 문구 변경

                    // content.textContent = "";


                    // @details CSS 효과 추가

                    content.style.border = "1px solid #FFB6C1";


                    // @details 포커스 지정

                    content.focus();

                }

            });


            // @breif 키보드 입력이 방생한 경우 실행

            content.addEventListener("keypress", function(event) {


                // @breif Enter키 입력시 실행

                if(event.key === "Enter") {


                    // @details 입력된 값이 빈값( null )인지 체크한다.

                    if(

                           content.textContent == ""

                        || content.textContent == null

                        || content.textContent == undefined

                        || (content.textContent != null

                        && typeof content.textContent == "object"

                        && !Object.keys(content.textContent).length == ""))

                    {


                        // @details 내용이 존재하지 않다면 data 태그의 기본값으로 되돌린다.

                        content.textContent = content.dataset.default;

                    } else {


                        // @details 내용의 수정이 완료되었다면 data 태그의 기본값도 바꿔준다.

                        content.dataset.default = content.textContent;

                    }


                    // @breif 수정 불가 상태로 되돌린다.

                    content.contentEditable = false;

                    content.style.border = "0px";

                }

            });

        });

    });

</script>




위 코드의 결과는 아래와 같이 직접 확인을 진행해 보자.




# 출력결과

번호

가수

노래

발매일

1

윤하

오렌지 첫사랑

2007-10-23

2

도원경

다시 사랑한다면

2001-05-01

3

더더

it's You

1998-11-01

4

박기영

시작

1999-04-07

5

이소은

오래오래

2002-12-21

주의해당 출력결과Internet Explorer에서는 정상적으로 작동하지 않습니다.



위에 가수, 노래, 발매일 항목을 마우스로 더블클릭( dblclick )하면 내용을 수정하고, 키보드 Enter 키를 눌러 변경한 내용을 반영할 수 있다.

( 단 공란( null )은 사용할 수 없게 처리되어 있다. )



또한 하나의 컬럼을 수정하던중 다른 컬럼을 더블클릭( dblclick )한 경우 수정중이던 컬럼영역은


data-default에 저장되어있는 기존값으로 다시 돌아가게 설계되어 있다.


이와같은 예외처리는 용도에 맞게 코드를 조금 손보면 바로 적용할 수 있을 것이다.





자체과제 : 심화코드 만들어보기






Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] Canvas로 이미지 서버에 전송하기 - Sample[JavaScript] Canvas로 이미지 서버에 전송하기 - Sample

Posted at 2020. 3. 6. 17:38 | Posted in JavaScript & jQuery/JavaScript




참고 : https://bugsdb.com/_ko/debug/14292f07a628fd12f3b6afc4a751f956






■ 캔버스로 생성한 이미지 파일 서버에 업로드 하기




# 소스코드 - 클라이언트 페이지 ( 이미지 전송 )

 canvas_upload.php

<html>

<head>

<meta charset="UTF-8">

<title>:: JavaScript 캔버스 이미지 업로드 ::</title>

<meta name="viewport" content="width=device-width">

<link type="text/css" rel="stylesheet" href="./css/modern.css"/>

<style type="text/css">

    .imgArea { text-align:center; }

    canvas, #uploadFile, #submitBtn { display:none; }

</style>

<script type="text/javascript">


    // @breif AJAX 통신 함수

    function getXMLHTTPRequest() {

        let request = false;

        try { request = new XMLHttpRequest(); }

        catch(err01) {

            try { request = new ActiveXObject("Msxml2.XMLHTTP"); }

            catch(err02) {

                try { request = new ActiveXObject("Microsoft.XMLHTTP"); }

                catch(err03) { request = false; }

            }

        }

        return request;

    }


    const ajax = getXMLHTTPRequest();


    // @breif 이미지 업로드 함수

    function uploadImgFilePrinted() {


        // @details 업로드 파일 정보를 받아온다.

        let fileInfo = document.getElementById("uploadFile").files[0];

        let reader = new FileReader();


        reader.onload = function() {


            // @details 업로드 버튼 이미지의 넓이와 높이에 맞게 썸네일을 생성을 위해 그 값을 받아온다.

            const btnWidth = document.getElementById("uploadImg").width;

            const btnHeight = document.getElementById("uploadImg").height;


            // @details 업로드 이미지 출력

            document.getElementById("uploadImg").src = reader.result;

            document.getElementById("uploadImg").width = btnWidth;

            document.getElementById("uploadImg").height = btnHeight;


            // @details 등록버튼 노출

            document.querySelector("#submitBtn").style.display = "inline";

        };


        if(fileInfo) {

            // @details readAsDataURL을 통해 업로드한 파일의 URL을 읽어 들인다.

            reader.readAsDataURL(fileInfo);

        }

    }


    function registryUploadImg() {

        if(confirm("업로드한 이미지를 업로드 하시겠습니까?") == true) {


            let upImage = new Image();

            upImage.src = document.getElementById("uploadImg").src;


            upImage.onload = function() {


                // @breif 캔버스 위에 이미지 그리기

                let canvas = document.querySelector("canvas");

                let canvasContext = canvas.getContext("2d");


                // @details 리사이즈할 이미지의 크기는, 현재 클라이언트에게 노출되어 있는 이미지 크기로 지정

                const btnWidth = document.getElementById("uploadImg").width;

                const btnHeight = document.getElementById("uploadImg").height;


                // @details 캔버스 생성 및 이미지 그리기

                canvas.width = btnWidth;

                canvas.height = btnHeight;

                canvasContext.drawImage(this, 0, 0, btnWidth, btnHeight);


                // @details AJAX 전송 데이터 설정

                const arrData =  {

                      "mode" : "imgFileUpload"

                    , "imgBase64" : canvas.toDataURL("image/jpeg")

                    , "imgFileName" : document.getElementById("uploadFile").files[0]['name']

                };


                ajax.open("POST", "./upload_image.php", true); // @details 비동기 방식 사용

                ajax.setRequestHeader("Content-Type", "application/json;charset=UTF-8;");

                ajax.send(JSON.stringify(arrData));


                ajax.onreadystatechange = function() {

                    if(ajax.readyState == 4) {

                        if(ajax.status == 200) {

                            const json = JSON.parse(ajax.responseText);

                            if(json.ret == "success") {

                                alert(json.message);

        } else {

                                alert(json.message);

                            }

                        } else {

                            alert(json.message);

                        }

                    }

                };

            };


        } else {

            return false;

        }

    }

</script>

<link rel="import" href="/edit_img.html">

</head>

<body>

<div class="windowFilm"></div>

<form id="uploadFrom" method="post">

    <input type="file" id="uploadFile" onChange="uploadImgFilePrinted();" accept="image/*"/>

    <div class="contents">

        <h1>캔버스&nbsp;업로드<span>샘플</span></h1>

        <div class="imgArea">

            <a href="javascript:;" onClick="document.getElementById('uploadFile').click();">

                <img id="uploadImg" src="./user-anonymous.png"/>

            </a>

            <br/><br/>

            <input id="submitBtn" type="button" onClick="registryUploadImg();" value="등록">

        </div>

        <canvas></canvas>

        <div class="copyright" style="bottom:0;">

            <p>Producer &copy; 사악미소</p>

        </div>

    </div>

</form>

</body>

</html> 




# 소스코드 - 서버 ( 이미지 파일 저장 )

 upload_image.php

<?php

$RetVal = array("ret"=>"fail", "error"=>"", "error_msg"=>"", "message"=>"");

$backUrl = $_SERVER['HTTP_REFERER'];


// @breif php://input은 내용의 유형에 관계없이 요청 HTTP 헤더 뒤에 모든 원시 데이터를 반환한다.

$data = json_decode(file_get_contents("php://input"), true);


switch($data['mode']) {


    // @breif ajax 이미지 업로드

    case "imgFileUpload" :


        // @breif base64로 암호화된 이미지 파일명 디코드

        $uploadCanvas = base64_decode(preg_replace("#^data:image/\w+;base64,#i", "", $data['imgBase64']));


        // @breif 파일명과 확장자를 분리 하여 담는다.

        $fileName = array_shift(explode(".", $data['imgFileName'])); // @details 이미지 파일 이름


        // @breif 이미지 파일명 변경

        $uploadImgName = $fileName."_".time().".jpg";


        // @breif 업로드할 이미지 경로 설정

        $uploadSrc = "./upload/".$uploadImgName;


        // @breif 이미지 파일 저장

        file_put_contents($uploadSrc, $uploadCanvas);


        // @breif 성공 여부 확인

        if(file_exists($uploadSrc) == TRUE) {

            $RetVal['ret'] = "success";

            $RetVal['message'] = "파일을 업로드 하는데 성공하였습니다.\n축하합니다.";

        } else {

            $RetVal['message'] = "파일을 업로드 하는데 실패하였습니다.\n다시 시도하여 주시기 바랍니다.";

        }


// @return 업로드 성공 / 실패 유무를 json 방식으로 웹 페이지에 전달한다.

        print json_encode($RetVal);

        return;


    break;


    default :


    $RetVal['message'] = "서버와의 연결 실패";

    print json_encode($RetVal);

        return;


    break;

}


header("location:".$backUrl);

?>





# 출력결과







관련포스팅#01 : [JavaScript] 이미지 파일 썸네일 생성하기

관련포스팅#02 : [JavaScript] Canvas를 통한 이미지 회전

관련포스팅#03 : [JavaScript] Canvas로 이미지 서버에 전송하기 - Sample

관련포스팅#04 : [jQuery] JCROP을 이용한 이미지 자르기 - Sample










Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[jQuery] JCROP을 이용한 이미지 자르기 - Sample[jQuery] JCROP을 이용한 이미지 자르기 - Sample

Posted at 2020. 2. 11. 13:29 | Posted in JavaScript & jQuery/jQuery





Jcrop 다운 : http://deepliquid.com/content/Jcrop.html

Jcrop API : https://jcrop.com/

GitHub : https://github.com/tapmodo/Jcrop





■ JCROP을 이용한 업로드한 크롭( CROP ) 하기





웹 브라우저 상에서 이미지를 업로드하고, 해당 이미지를 편집 하는 기능을 제작하게 되었다.


HTML5의 캔버스를 통해 업로드한 이미지를 똑같이 복사하여, 작업영역을 만들고.


캔버스에서 작업이 완료된 그림을 다시 원본 이미지와 교체하는형태로 서버에 업로드 하지 않고 작업하는것을 마무리 하였다.




# 소스코드

<html>

<head>

<meta charset="UTF-8">

<title>:: JavaScript 캔버스 이미지 업로드 ::</title>

<meta name="viewport" content="width=device-width">

<link type="text/css" rel="stylesheet" href="./css/modern.css"/>

<link type="text/css" rel="stylesheet" href="http://jcrop-cdn.tapmodo.com/v0.9.12/css/jquery.Jcrop.min.css"/>

<style type="text/css">

    .imgArea { text-align:center; }

    canvas, #uploadFile, #editBtn, #cutBtn { display:none; }

    body { overflow:hidden };

</style>

<script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.min.js"></script>

<script type="text/javascript" src="http://jcrop-cdn.tapmodo.com/v0.9.12/js/jquery.Jcrop.min.js"></script>

<script type="text/javascript">

    let jcropApi = null;


    // @breif 이미지 크롭 영역지정 UI 나타내기

    function imgCropDesignate() {


        let editWidth = jQuery("#editImg").width();

        let editHeight = jQuery("#editImg").height();

       

        // @breif jcrop 실행시 크롭영역을 미리 세팅

        let x1 = window.screen.width / 2 - editWidth;

        let y1 = window.screen.height / 2 - editHeight;

        let x2 = editWidth / 1.5;

        let y2 = editHeight / 1.5;


        // @breif jcrop 실행

        jQuery("#editImg").Jcrop({

              bgFade : true

            , bgOpacity : .2

            , setSelect : [ x1, y1, x2, y2 ]

            , onSelect : updateCoords

        }, function() {

            jcropApi = this;

        });

        

        jQuery("#editBtn").css("display", "none");

        jQuery("#cutBtn").css("display", "inline");

    }

    

    // @breif 지정된 크롭 한 영역( 좌표, 넓이, 높이 )의 값을 보관하는 함수

    function updateCoords(crap) {

        jQuery("#xAxis").val(crap.x);

        jQuery("#yAxis").val(crap.y);

        jQuery("#wLength").val(crap.w);

        jQuery("#hLength").val(crap.h);

    }


    // @breif 크롭한 영역 잘라내고 추출하기

    function imgCropApply() {


        if(parseInt(jQuery("#wLength").val()) == "NaN") {

            alert("이미지를 크롭한 이후\n자르기 버튼을 클릭하세요.");

            return false;

        } else {


            let editImage = new Image();

            editImage.src = jQuery("#editImg").attr("src");


            editImage.onload = function() {


                // @breif 캔버스 위에 이미지 그리기

                let canvas = document.querySelector("canvas");

                let canvasContext = canvas.getContext("2d");


                // @breif 캔버스 크기를 이미지 크기와 동일하게 지정

                canvas.width = jQuery("#wLength").val();

                canvas.height = jQuery("#hLength").val();

                                

                canvasContext.drawImage(

                      this

                    , jQuery("#xAxis").val()        // 자르기를 시작할 x좌표

                    , jQuery("#yAxis").val()        // 자르기를 시작할 y좌표

                    , jQuery("#wLength").val()    // 잘라낸 이미지의 넓이

                    , jQuery("#hLength").val()    // 잘라낸 이미지의 높이

                    , 0                                         // 캔버스에 이미지를 배치할 x좌표

                    , 0                                         // 캔버스에 이미지를 배치할 y좌표

                    , jQuery("#wLength").val()    // 사용할 이미지의 넓이(이미지 스트레칭 또는 축소)

                    , jQuery("#hLength").val()    // 사용할 이미지의 높이(이미지 스트레칭 또는 축소)

                );


                // @breif 편집한 캔버스의 이미지를 화면에 출력한다.

                let dataURI = canvas.toDataURL("image/jpeg");

                jQuery("#editImg").attr("src", dataURI);

                

                // @breif 이미지의 크기는 자른 이미지와 동일하게 지정

                jQuery("#editImg").css("width", jQuery("#wLength").val());

                jQuery("#editImg").css("height", jQuery("#hLength").val());

            };


            jQuery("#cutBtn").css("display", "none");


            // @details JCROP을 종료한다.

            jcropApi.destroy();

    jcropApi = null;

        }

    }

    // @breif 이미지 업로드 함수

    function uploadImgFilePrinted() {


        // @details 업로드 파일 정보를 받아온다.

        let fileInfo = document.getElementById("uploadFile").files[0];

        let reader = new FileReader();


        reader.onload = function() {


            // @details 업로드 이미지 출력

            jQuery("#editImg").attr("src", reader.result);

            

            // @details 이미지 크기를 제목 영영과 같게 출력

            jQuery("#editImg").css("width", jQuery("h1").width());

            

            // @details 이미지 업로드 기능 제거, 추가 업로드 방지

            jQuery("#editImg").parent("a").removeAttr("onClick");

            

            // @details 편집버튼 노출

            jQuery("#editBtn").css("display", "inline");

            

            canvasDrawImage(function() {

            alert("이미지 업로드가 완료되었습니다.");

            });

        };


        if(fileInfo) {     

            // @details readAsDataURL을 통해 업로드한 파일의 URL을 읽어 들인다.

            reader.readAsDataURL(fileInfo);

        }

    }

    // @breif 캔버스 이미지 생성

    function canvasDrawImage(callback) {

        let prepImage = new Image();

        prepImage.src = jQuery("#editImg").attr("src");


        prepImage.onload = function() {


            // @details 캔버스 위에 이미지 그리기

            // jQuery("canvas") 와같은 명령은 사용할 수 없다.

            let canvas = document.querySelector("canvas");

            let canvasContext = canvas.getContext("2d");


            canvas.width = jQuery("#editImg").width();

            canvas.height = jQuery("#editImg").height();

            canvasContext.drawImage(this, 0, 0, jQuery("#editImg").width(), jQuery("#editImg").height());


            // @details 캔버스의 이미지

            let dataURI = canvas.toDataURL("image/jpeg");

            jQuery("#editImg").attr("src", dataURI);

            

            callback();

        };

    }

</script>

</head>

<body>

<input type="hidden" id="xAxis" value="0" placeholder="선택영여역의_x좌표"/>

<input type="hidden" id="yAxis" value="0" placeholder="선택영여역의_y좌표"/>

<input type="hidden" id="wLength" value="0" placeholder="선택영여역의_w넓이"/>

<input type="hidden" id="hLength" value="0" placeholder="선택영여역의_h높이"/>

<input type="file" id="uploadFile" onChange="uploadImgFilePrinted();" accept="image/*"/>

<div class="contents">

    <h1>이미지&nbsp;자르기<span>샘플</span></h1>

    <div class="imgArea">

        <a href="javascript:;" onClick="jQuery('#uploadFile').click();">

            <img id="editImg" src="./user-anonymous.png"/>

        </a>

        <br/><br/>

        <input id="editBtn" type="button" onClick="imgCropDesignate();" value="편집"/>

        <input id="cutBtn" type="button" onClick="imgCropApply();" value="자르기"/>

    </div>

    <canvas></canvas>

    <div class="copyright" style="bottom:0;">

        <p>Producer &copy; 사악미소</p>

    </div>

</div>

</body>

</html> 





# 출력결과





관련포스팅#01 : [JavaScript] 이미지 파일 썸네일 생성하기

관련포스팅#02 : [JavaScript] Canvas를 통한 이미지 회전

관련포스팅#03 : [JavaScript] Canvas로 이미지 서버에 전송하기 - Sample

관련포스팅#04 : [jQuery] JCROP을 이용한 이미지 자르기 - Sample






  1. 비밀댓글입니다
    • 2020.03.25 08:33 신고 [Edit/Del]
      디자인을 물어보시는거라면
      https://wikibook.co.kr/modern-web-design-book/
      의 예제소스의 CSS를 조금 손보아서 사용하였습니다.
      정확한 파일명은 기억이 나지 않네요

Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] 파일업로드시 용량 검사하기[JavaScript] 파일업로드시 용량 검사하기

Posted at 2019. 12. 26. 11:25 | Posted in JavaScript & jQuery/JavaScript



참고 : https://zzznara2.tistory.com/617




■ 파일업로드시 용량 검사하기




# 소스코드

<html>

<head>

<title>:: JAVASCRIPT 파일업로드 ::</title>

<script type="text/javascript">

    function imgFileUpload() {


        /// @brief 업로드할 이미지의 크기( Byte )를 구해온다.

        const imgSize = document.getElementById("personImg").files[0].size;


        /// @brief 업로드할 이미지 사이즈의 크기는 4MB 이하로 설정

        const maxSize = 4 * 1024 * 1024;


        /// @brief 이미지

        if(imgSize > maxSize) {


            alert("첨부할 수 있는 이미지 파일은 4MB 이하여야 합니다.");

            document.getElementById("personImg").focus();

            return false;


        } else {


            alert("업로드 가능한 이미지입니다.");


        }

    }

</script>

</head>

<body>

<form enctype="multipart/form-data" id="upFrm" method="post">

    <input type="file" id="personImg" name="personImg" value=""/>

    <input type="button" onClick="imgFileUpload();" value="업로드"/>

</form>

</body>

</html>




# 출력결과 - 수정예정






관련문서 : [JavaScript] 파일업로드시 확장자 검사하기







Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[API] Bittly API v4 연동, 단축 URL 생성하기 - PHP[API] Bittly API v4 연동, 단축 URL 생성하기 - PHP

Posted at 2019. 12. 23. 19:34 | Posted in API/Bitly




참고 : https://stackoverflow.com/questions/55681871/how-to-shorten-url-using-php-bitly-v4?answertab=active#tab-top





■ Bittly API v4 토큰 발급받기




① 먼저 Bittly 계정이 필요하다.

    가지고 있는 Bittly계정이 존재하지 않다면 https://bitly.com/a/sign_up 페이지에 접속하여 계정을 생성한다.






② 가입된 계정이 준비되었다면 https://app.bitly.com/ 페이지에 접근한다.(로그인 되어 있지 않은 상태로 접근 불가)

    자신의 계정정보가 노출되는 페이지에 접속 했다면 상단 우측의 메뉴 항목을 클릭한다.






③  자신의 계정을 클릭한다.






④ Generic Access Token 카테고리를 클릭한다.






패스워드를 입력하고 클릭하면 화면 하단에 GENERATE TOKEN 버튼이 나타난다.

     GENERATE TOKEN 버튼을 클릭한다.





토큰이 발급된 것을 확인 할 수 있다.










■ Bittly API v4 연동하여 짧은 URL 생성하기





PHP에서 Bittly API와 연동하여 짧은 URL을 생성해 보도록 하겠다.


PHP의 cURL을 사용하였다.




# 소스코드

<?php


/// @brief URI 값 생성

$getUri = "num=1&lang=ko";


/// @brief 접근할 URL 주소 생성

$longUrl = "http://도메인주소?".$getUri;


/// @brief  생성한 URL을 $data['long_url']에 담고 JSON 형태로 변환한다.

$data['long_url'] = $longUrl;

$payload = json_encode($data);


/// @brief BITLY API 접근 URL

$bitApi = "https://api-ssl.bitly.com/v4/bitlinks";


/// @brief 발급받은 BITLY API 토큰

$bitToken = "발급받은 API 토큰 값";


/// @brief CURL 사용

$cURL = curl_init();

curl_setopt($cURL, CURLOPT_URL$bitApi);

curl_setopt($cURL, CURLOPT_CUSTOMREQUEST, "POST");

curl_setopt($cURL, CURLOPT_POSTFIELDS$payload);

curl_setopt($cURL, CURLOPT_RETURNTRANSFER, TRUE);

curl_setopt($cURL, CURLOPT_HTTPHEADER, array(

  "Authorization:Bearer ".$bitToken         // Bearer { $token } (공백필수)

, "Content-Type:application/json"

, "Content-Length:".strlen($payload)

)

);


/// @brief 결과값 조회

$result = json_decode(curl_exec($cURL), TRUE);


echo "<pre>";

print_r($result);

echo "</pre>";


/// @brief 출력결과

if(isset($result['link']) == 1) {

echo $result['link'];

}

?> 




# 출력결과







'API > Bitly' 카테고리의 다른 글

[API] Bittly API v4 연동, 단축 URL 생성하기 - PHP  (0) 2019.12.23

Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] 체크박스 전체 선택 - Sample[JavaScript] 체크박스 전체 선택 - Sample

Posted at 2019. 12. 19. 11:34 | Posted in JavaScript & jQuery/JavaScript




■ 전체영역을 선택하는 체크박스 샘플 코드




# 소스코드

<html>

<head>

<title>:: JavaScript 체크박스 ::</title>

<script type="text/javascript">


    // @command 전체선택

    function allCheckedBox(obj) {


        // @brief 선택한 체크박스의 클래스 명칭을 가져온다.

        const termClassobj.getAttribute("class");


        // @brief 선택한 클래스명과 같은 클래스의 갯수

        console.log(document.getElementsByClassName(termClass).length);


        Array.prototype.forEach.call(document.getElementsByClassName(termClass), function(element, index, array) {


            // @brief 엘리먼트의 값 출력

            console.log(element.value);


            // @brief 선택한 클래스의 첫번째 checkbox의 상태가 체크가 되있는 경우

            if(document.getElementsByClassName(termClass)[0].checked == true) {


                // @brief 같은 클래스명을 가진 모든 checkbox의 상태를 선택 완료 처리 한다.

                element.checked = true;

            }


            // @brief 선택한 클래스의 첫번째 checkbox의 상태가 체크가 해제된 경우

            else {


                // @brief 같은 클래스명을 가진 모든 checkbox의 상태를 선택 해제 처리 한다.

                element.checked = false;

            }

        });

    }


    // @command 개별 선택이 이루어진 경우에 전체값 체크의 예외처리

    function eachCheckedBox(obj) {


        // @brief 선택한 체크박스의 상태가 선택해제인 경우

        if(obj.checked == false) {


            // @brief 선택한 체크박스의 클래스 명칭을 가져온다.

            const termClass = obj.getAttribute("class");


            // @brief 첫번째 checkbox의 상태가 체크가 되어있는경우

            if(document.getElementsByClassName(termClass)[0].checked == true) {


                // @brief 첫번째 checkbox의 상태를 체크해제한다.

                document.getElementsByClassName(termClass)[0].checked = false;

            }

        }

    }

</script>

</head>

<body>

     <h1>■ 체크박스 전체 선택 - SAMPLE</h1>


    <!-- @brief 전체의 선택의 경우 반드시 index값이 0인 첫번째에 위치해야 한다. -->

    <label>

        <input type="checkbox" class="neHeros" value="" onChange="allCheckedBox(this);"/>&nbsp;전체

    </label>


    <!-- @brief 개별선택될 체크박스들 -->

    <label>

        <input type="checkboxclass="neHeros" value="D" onChange="eachCheckedBox(this);"/>&nbsp;데몬헌터

    </label>

    <label>

        <input type="checkboxclass="neHeros" value="W" onChange="eachCheckedBox(this);"/>&nbsp;워든

    </label>

    <label>

        <input type="checkboxclass="neHeros" value="K" onChange="eachCheckedBox(this);"/>&nbsp;키퍼 오브 더 그루브

    </label>

    <label>

        <input type="checkboxclass="neHeros" value="P" onChange="eachCheckedBox(this);"/>&nbsp;프리시스 오브 더 문

    </label>

</body>

</html>




# 출력결과







Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기