[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 속성을 가진경우
    var content = document.querySelector( "[contenteditable]" );
    var edtButton = document.querySelector( "button" );

    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 속성을 가진경우

    var 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] 정규 표현식 사용방법[JavaScript] 정규 표현식 사용방법

Posted at 2020. 5. 7. 02:25 | Posted in JavaScript & jQuery/JavaScript




출처 : 모던 웹을 위한 JavaScript + jQuery 입문

참고 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/정규식



정규 표현식은 자바스크립트의 내장 객체이다.


정규 표현식은 문자열의 패턴을 검사할때 사용된다.


원래는 펄( Perl ) 프로그래밍 언어에서 사용한 객체인데, 너무 유용해서 현재는 많은 프로그래밍 언어에서 사용되고 있다.




■ 정규 표현식의 객체




#01. 정규 표현식 객체의 생성


# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @details 정규표현식의 사용법 ①

        const regExp1 = new RegExp( "text" );

        console.log( regExp1 );


        // @details 정규표현식의 사용법 ② - 일반적으로 간단한 ②번 방법이 많이 사용됨

        const regExp2 = /text/;

        console.log( regExp2 );

    });

</script>

</head>

</html>



# 출력결과





#02. 정규 표현식의 메서드



정규 표현식은 문자열 처럼 만들어 사용가능하다.


메서드 이름

설   명

 test( )

 · 정규 표현식과 일치하는 문자열이 있으면 true를 dkslaus, false를 리턴한다.

 exec( )

 · 정규 표현식과 일치한느 문자열을 리턴한다.




# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const regExp = new RegExp( /Fox/ );

        const string = "FireFox Chrome Opera Edge Safari";


        // @breif 메서드를 사용한다.

        let output = regExp.test( string );


        // @breif 출력한다.

        alert( output );

    });

</script>

</head>

</html> 




# 출력결과



변수 string 내부에 정규 표현식과 일치하는 문자열 "Fox"가 있으므로 true를 출력한다.


정규 표현식은 이렇게 정규 표현식의 메서드를 곧바로 사용하는 것보다는 문자열 객체의 메서드와 함께 사용하는것이 일반적이다.





#03. 정규 표현식을 사용하는 String 객체의 메서드


메서드 이름

설   명

 match( 정규_표현식 )

 · 정규 표현식과 일치하는 부분을 리턴한다.

 replace( 정규_표현식, 문자열 )

 · 정규 표현식과 일치하는 부분을 새로운 문자열로 바꾼다.

 search( 정규_표현식 )

 · 정규 표현식과 일치하는 부분의 위치를 리턴한다.

 split( 정규_표현식 )

 · 정규 표현식을 기준으로 문자열을 잘라 배열을 리턴한다.



아래는 split( ) 메서드를 사용한 예제이다.


split( ) 메서드의 매개 변수에 정규 표현식을 넣기만 하면된다.



# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const regExp = new RegExp( /Explorer/ );

        const string = "FireFox Chrome Explorer Opera Edge Safari";


        // @breif 메서드를 사용한다.

        let output = string.split( regExp );


        // @breif 출력한다.

        alert( output );

    });

</script>

</head>

</html>




split( ) 메서드는 정규 표현식을 기준으로 문자열을 잘라 배열로 만들어 리턴한다.




# 출력결과









■ 정규 표현식 - 대체 문자




정규 표현식을 사용하면 문자열의 객체의 replace( ) 메서드를 사용하여 대체문자를 삽입할 수 있다.




#01. 기호를 이용하여 문자 대체하기



정규 표현식 기호

설   명

 $&

 · 일치하는 문자열

 $`

 · 일치하는 부분의 앞부분 문자열 ( 참고 : ( ` ) 는 숫자 1키 좌측의 기호이다. )

 $'

 · 일치하는 부분의 뒷부분 문자열

 $1, $2, $3 ~

 · 그룹, $1 부터 시작하여 계속 +1씩 숫자가 증가되는 식으로 사용한다.



아래 코드는 문자열 객체의 replace( ) 메서드를 사용해서 정규 표현식에 일치하는 문자열을 "+$&+"로 변경한다.



# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const regExp = new RegExp( /a/ );

        const string = "FireFox Chrome Explorer Opera Edge Safari";


        // @breif 메서드를 사용한다.

        let output = string.replace( regExp, "+$&+" );


        // @breif 출력한다.

        alert( output );

    });

</script>

</head>

</html>



# 출력결과





대체 문자는 이렇게 정규 표현식의 특정 내용과 매치되어 문자를 대체해 출력해주는 문자이다.


이 방식을 좀 더 쉽게 이해하기 위해서 아래와 같은 코드를 작성해 보자.


문자열 객체의 replace( ) 메서드의 매개 변수에 함수를 추가할 수 있다.


매개 변수로 넣은 함수의 매개 변수에는 정규 표현식에 대응하는 문자열이 입력되며 리턴하는 문자열로 대체된다.



# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const regExp = new RegExp( /a/ );

        const string = "FireFox Chrome Explorer Opera Edge Safari";


        // @breif 메서드를 사용한다.

        let output = string.replace( regExp, function( value ) {

            return "+" + value + "+";

        });


        // @breif 출력한다.

        alert( output );

    });

</script>

</head>

</html>




# 출력결과




따라서 예제코드를 실행해 보면 동일한 결과 출력되는 것을 확인 할 수 있다.



# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const regExp = new RegExp( /(r)(o)(m)(e)/ );

        const string = "FireFox Chrome Explorer Opera Edge Safari";


        // @breif 메서드를 사용한다.

        const output = string.replace( regExp, "+$1=$2=$3+" );


        // @breif 출력한다.

        alert( output );

    });

</script>

</head>

<body>

</body>

</html> 




각각의 문자가 대체되므로 $1, $2, $3을 직접 출력하는 것이 아니라


아래와 같이 r, o, m을 출력한다.




# 출력결과









■ 정규 표현식 - 플래그 문자




플래그 문자는 다음과 같은 방법으로 사용된다.


정규 표현식 기호

설   명

 g

 · 전역 비교를 수행한다.

 i

 · 대소문자를 가리지 않고 비교한다.

 m

 · 여러 줄의 검사를 수행한다.



플래그 문자를 생성할 때에는 뒤에 붙여 사용하며, 생성자를 사용할 때에는 두 번째 매개 변수에 입력한다.


플래그 문자 위치에 들어가는 플래그 문자의 순서는 어떻게 되어도 상관 없다.




# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const regExp = new RegExp( /e/ig );  // @details i와 g의 순서는 변경돼도 상관없다.

        const string = "FireFox Chrome Explorer Opera Edge Safari";


        // @breif 메서드를 사용한다.

        const output = string.replace( regExp, "+$&+" );


        // @breif 출력한다.

        alert( output );

    });

</script>

</head>

<body>

</body>

</html> 



# 출력결과










■ 정규 표현식 - 앵커 문자




앵커 문자는 문자열의 앞과 뒤를 구분해주는 정규 표현식 기호이다.


정규 표현식 기호

설   명

 ^ABC

 · 맨 앞 문자가 ABC

 ABC$

 · 맨 뒤 문자가 ABC



앵커 문자를 사용하면 원하는 부분을 찾을 수 있다.




#01. 앵커 문자



# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const regExp = new RegExp( /^f/ig );

        const string = "FireFox\nChrome\nExplorer\nOpera\nEdge\nSafari";


        // @breif 메서드를 사용한다.

        const output = string.replace( regExp, "+$&+" );


        // @breif 출력한다.

        alert( output );

    });

</script>

</head>

</html>




# 출력결과






#02. 앵커 문자와 플래그 문자( m ) 의 동시 사용




이번에는 앵커 문자와 플래그 문자( m )을 사용하여 문자열이 여러 줄일경우,


각각의 줄을 개별적인 문자열로 인지하고 검사할 수 있게 해주는 플래그 문자이다.



# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const regExp = new RegExp( /^m/igm );

        const string = "Mask The Red\nMask The Pink\nMask The Blue\nMask The Green\nMask The Yellow\nMask The Black";


        // @breif 메서드를 사용한다.

        const output = string.replace( regExp, "+$&+" );


        // @breif 출력한다.

        alert( output );

    });

</script>

</head>

<body>

</body>

</html> 




# 출력결과




코드를 실행하면 위와같이 여러줄에 걸친 대소 문자를 무시한 전역 검사를 수행한다.


플래그 문자( m )을 사용하였기에 모든 줄의 문자가 범위에 지정된다.









■ 정규 표현식 - 메타 문자




#01. 메타 문자의 범위 지정



메타 문자는 자바 스크립트의 정규 표현식 객체가 갖는 가장 유용한 기능이다.


기호

설 명

.

 · 아무 글자

[ abc ]

 · 괄호 안의 글자

[ ^abc ]

 · 괄호 안의 글자 제외

[ a - z ]

 · 알파벳 a부터 z까지

[ A - Z ]

 · 알파벳 A부터 Z까지

[ 0 - 9 ]

 · 숫자 0부터 9까지

[ ㄱ -ㅎ ]

 · 한글 자음 ㄱ부터 ㅎ까지

[ ㅏ - ㅑ ]

 · 한글 모음 ㅏ - I 까지

[ 가 - 힣 ]

 · 한글 단어 가 - 힣 까지( 전체 )




위 표의 예는 알파벳과 한글의 최대 범위를 예로 설명하지만.


[ h - k ] 의 형태로 범위를 한정하여 지정할 수 도 있다.


아래 예제를 살펴보면 [ a j ]  메타 문자와 플래그를 함께 사용하여 a 또는 j, A 또는 J를 검사한다.



<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const regExp = new RegExp( /[oi]/ig );

        const string = "FireFox Chrome Explorer Opera Edge Safari";


        // @breif 메서드를 사용한다.

        const output = string.replace( regExp, "+$%+" );


        // @breif 출력한다.

        alert( output );

    });

</script>

</head>

</html> 



코드를 실행하면 o, i, O, J 문자가 대체된다.







#02. 패턴 매칭 시키기



주민등록 번호를 검사하는 정규 표현식을 만들어 보자.


앞에 여섯 개의 글자가 오고 중간에 ` - `가 들어가고 그 뒤에 일곱개의 글자가 나오면 된다.


<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const regExp = new RegExp( /......-......./ );

        const string = "001234-1234567";


        // @breif 메서드를 사용한다.

        const output = string.replace( regExp, "+$&+" );


        // @breif 출력한다.

        alert( output );

    });

</script>

</head>

</html>



주민등록 번호 형식을 넣으면 양 끝에 +를 추가해서 출력한다.


패턴 매칭을 수행한 결과이다.







#03. 자바스크립트에서 추가된 정규 표현식의 메타문자



자바스크립트의 정규표현식은 메타 문자를 추가로 지원한다.


기호 

설 명

\d

 · 숫자

\w

 · 아무 단어( 숫자 포함 )

\s

 · 공백 문자 ( 탭, 띄어쓰기, 줄 바꿈)

\D

 · 숫자 아님

\W

 · 아무 단어 아님

\S

 · 공백 문자 아님



이를 혼합하면 주민등록번호 검사를 좀더 구체적으로 할 수 있는데


주민등록번호 뒤에 위치히나느 7개의 숫자 중 첫번째 숫자는 1, 2, 3, 4중 하나이므로


입력한 7번째의 값이 1, 2, 3, 4중 하나가 맞는지 확인해 보자.



# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const regExp = new RegExp( /\d\d\d\d\d\d-[1234]\d\d\d\d\d\d/ );

        const string = "001234-3723584";


        // @breif 메서드를 사용한다.

        const output = regExp.test( string );


        if( output == true ) {

            alert( "주민등록번호 형식에 규합합니다." );

        } else {

            alert( "주민등록번호 형식에 일치하지 않습니다." );

        }

    });

</script>

</head>

</html>




# 출력결과










■ 정규 표현식 - 수량문자




자바스크립트의 정규 표현식은 수량 문자를 지원한다.


기호 

설  명 

a+

 · a가 적어도 1개 이상

a*

 · a가 0개 또는 여러개

a?

 · a가 0개 또는 1개

a { 5 }

 · a가 5개

a {2, 5}

 · a가 2개 ~ 5개

a { 2 . }

 · a가 2개 이상

a { . 2 }

 · ar가 2개 이하




#01. 수량 문자를 사용한 범위 지정



위에서 우리는 주민등록번호의 패턴을 검사하는 예제를 진행 하였는데.


\d 기호를 몇 번씩이나 사용하였기에 실수하는 경우가 발생할 수 있다.


수량 문자를 사용하여 위 제를 조금 수정해 보자.



# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        // const regExp = new RegExp( /\d\d\d\d\d\d-[1234]\d\d\d\d\d\d/ );

        const regExp = new RegExp( /\d{6}-[1234]\d{6}/ );

        const string = "001234-1234567";


        // @breif 메서드를 사용한다.

        const output = regExp.test( string );


        if( output == true ) {

            alert( "주민등록번호 형식에 규합합니다." );

        } else {

            alert( "주민등록번호 형식에 일치하지 않습니다." );

        }

    });

</script>

</head>

</html>



이제 예제를 실행해보면


동일한 결과를 출력하는 것을 확인 할 수 있다.



# 출력결과






#02. 문자 열의 반복 체크



정규 표현식은 괄호 수량 문자와 함께 사용하면 특정 문자열의 반복을 체크 할 수 있다.



# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const regExp = new RegExp( /(na)+/ );

        const string = "banana";


        // @breif 메서드를 사용한다.

        const output = string.replace( regExp, "+$&+" );


        // @breif 출력한다.

        alert( output );

    });

</script>

</head>

</html>



# 출력결과











■ 정규 표현식 - 선택 문자




선택 문자는 ` 또는(or) `의 역할을 수행하는 정규 표현식 기호이다.


정규 표현식 기호 

설   명

( abc | def )

 · abc 또는 def를 선택한다.



선택 문자는 지금까지 학습한 모든 정규 표현식 기호와 함께 사용할 수 있다.



# 소스코드

<html>

<head>

<title>:: JavaScript 정규표현식 ::</title>

<script type="text/javascript">

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


        // @breif 변수를 선언한다.

        const string = prompt( "소문자 또는 숫자로만 구성된 단어를 입력하세요.", "단어" );

        const regExp = new RegExp( /([0-9]|[a-z])/g );


        // @breif 출력한다.

        if( string.replace(regExp, "").length == 0 ) {

            alert( "SUCCESS" );

        } else {

            alert( "FAIL" );

        }

    });

</script>

</head>

</html> 




# 출력결과









해당 포스팅은 [한빛미디어] 모던 웹을 위한 JavaScript + jQuery 입문서의 내용을 정리한 것이다.


아무래도 책이라는 분량 때문이라도 한계가 있기에.


좀더 자세한 정규 표현식 및 대응되는 함수에 대한 설명은


https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/정규식


해당 링크의 내용을 좀더 참고하면 좀더 심화단계로 넘어갈 수 있을것이다.








Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] 휴대폰 사진 업로드시 회전 방지[JavaScript] 휴대폰 사진 업로드시 회전 방지

Posted at 2020. 3. 30. 16:11 | Posted in JavaScript & jQuery/JavaScript






■ 휴대폰 사진 업로드시, 사진이 원하는 방향으로 올라가지 않는경우





사실 해당 포스팅의 제목인 「 휴대폰 사진 업로드시 회전 방지 」 라고 적었지만 이건 사실 어그로를 끌기위한 그런 제목이고


해당 포스팅은 그 해결방법을 제시하기 위한 


휴대폰, 스마트폰의 카메라로 찍은 사진을 웹 브라우저를 통해 업로드 할경우,


이미지의 가로, 세로가 변경되어 등록되는 경우가 존재한다.


이러한 이유는 EXIF( Exchangeable Image File Format )의 회전값 변경이 반영되지 않기에 생기는 이유인데.


아래 이미지는 초기 스마트 폰에서 자주 볼 수 있었던 문제이다.

( 자이로 센서( Gyro Sensor ) 등의 기술 발전으로 이런 문제는 많이 해결 되었지만, 이미지의 편집등 다른 작업 과정으로 현재에도 이런 문제를 맏닥드릴 수 있다. )









가로로 찍은 이미지의 경우 스마트폰 상에서는 분명 정상적으로 보여주지만.


실제 이미지의 EXIF 값을 보면 회전정보( Orientation )가 90° CW 가 적용되어 있는것을 알 수 있다.


이를 회전정보 값을 브라우저에서는 인식하지 않고 보여지는 문제이다.







   # EXIF( Exchangeable Image File Format ) 란?



   디지털 카메라 등에서 사용되는 이미지 파일 메타데이터 포맷으로,


   카메라가 촬영한 사진, 녹음파일에 시간 등의 각종 정보를 담기 위해 개발되었다. 즉, 


   JPEG, TIFF 6.0과 RIFF, WAV 포맷에 이미지나 소리에 대한 정보를 추가로 기록할 수 있다.


   디지털카메라의 보급으로 널리 활성화되었고 이미지 메타데이터의 사실상 표준 지위에 있다.


   EXIF 데이터는 이미지 파일의 일부로 저장되며,


   EXIF 데이터를 지원하는 소프트웨어 사용 시 이미지를 변경해도 데이터를 보존한다.



   출처 : 나무위키( https://namu.wiki/w/EXIF )






간단하게 이미지 파일 하나를 선택하여 마우스 오른쪽 버튼을 클릭하고


오른쪽으로 회전( T ) 을 선택해 보자.







회전 정보 : 90° CW 로 반영된 것을 확인할 수 있다.


이 렇게 회전된 파일을 <img src="스토브리그.jpg">로 올려서 브라우저로 확인을 해 본다면.



# 소스코드

<html>

<head>

<title>:: 스토브리그 ::</title>

<style type="text/css">

/* image-orientation:from-image; */

/* 포스팅 작성일 기준으로 파이어 폭스만 가능 */

</style>

</head>

<body>

<img src="stoveleague.jpg"/>

</body>

</html> 




# 출력결과




회전 정보 : 90° CW가 반영이 <img> 태그를 사용한 경우


브라우저에서 다시 정방향으로 돌려서 출력하는 모습을 확인 할 수 있다.


그렇지만 그냥 브라우저상에서 이미지 경로를 직접 입력하여 호출하는 경우


위 출력결과처럼 




현재 파이어 폭스 브라우저의경우 CSS에 image-orientation:from-image; 를 넣어주는 것만으로도


회전정보 값을 읽어들여 <img> 태그에 반영할 수 있지만


아직까지 크롬등의 다른 브라우저에서는 CSS4의 실험적 기능이기에 적용되어 있지 않다고 한다.


결국 자동으로 이러한 상황을 해결 할 수는 없는 상황이기에


사용자의 폰, 찍은 각도에 따라 업로드시 문제가 발생할 수 있다.









GitHub : https://github.com/exif-js/exif-js





■ EXIF-JS를 이용하여, 이미지 파일의 EXIF 정보 가져오기




예제 진행하기에 앞서 아래와 같이 스마트폰으로 촬영한 이미지 파일 하나의


ORIENTATION( 회전 정보 )를 변경하여 아예 이미지를 뒤집어 보자.





해당 포스팅의 예제와 바로 이어지는 예제는


위와 같이 준비한 이미지로 진행을 해보자.




# 소스코드

<html>
<head>
<title>:: JavaScript 이미지 EXIF 정보 추출 ::</title>
<style type="text/css">
    table {
        border-collapse:collapse;
        border:1px #000000 solid;
        width:100%;
    }

    table > thead > tr > th {
        background-color:#FFC0CB;
    }

    table > tbody > tr > td:nth-child(odd) {
        text-align:center;
    }

    table > tbody > tr > td:nth-child(even) {
        padding-left:10px;
    }

    #thumbnailImg {
        width:100%;
        height:auto;
    }
</style>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/exif-js"></script>
<script type="text/javascript">
    function uploadImgPreview() {

        // @breif 업로드 파일 읽기
        const fileInfo = document.getElementById( "upImgFile" ).files[0];
        const reader = new FileReader();

        // @details readAsDataURL( )을 통해 파일을 읽어 들일때 onload가 실행
        reader.onload = function() {

            EXIF.getData(fileInfo, () => {

                const tags = EXIF.getAllTags( fileInfo );

                for( let key in tags ) {

                    // @details 화면에 출력할 메타데이터 정보 테이블 행( row )을 만든다.
                    document.querySelector( "tbody" ).appendChild( document.createElement( "tr" ) );

                    // @breif 메타 데이터 : 키
                    let colKey = document.createElement( "td" );
                    colKey.innerText = key;
                    document.querySelector( "tbody > tr:last-child" ).appendChild( colKey );

                    // @breif 메타 데이터 : 값
                    let colData = document.createElement( "td" );
                    colData.innerText = JSON.stringify( tags[key], null, "\t" );
                    document.querySelector( "tbody > tr:last-child" ).appendChild( colData );
                }
            });

            // @details 파일의 URL을 Base64 형태로 가져온다.
            document.getElementById("thumbnailImg").src = reader.result;
        };

        if( fileInfo ) {

            // @details readAsDataURL( )을 통해 파일의 URL을 읽어온다.
            reader.readAsDataURL( fileInfo );
        }
    }
</script>
</head>
<body>
    <!-- @breif accept 태그는 파일 업로드시 그것을 이미지 파일로 제한한다. -->
    <input type="file" id="upImgFile" onChange="uploadImgPreview();" accept="image/*">
    <hr/>
    <img id="thumbnailImg" src="">
    <hr/>
    <table border="1">
        <thead>
            <tr>
                <th>메타</th>
                <th>값</th>
            </tr>
        </thead>
        <tbody></tbody>
    </talbe>
</body>
</html>




# 출력결과










참고 : https://www.impulseadventure.com/photo/exif-orientation.html





■ <IMG> TAG에 ORIENTATION 으로 축 보정하기





그럼 이제 이미지 EXIF 정보에서 Orientation 정보를 가지고 와서 이미지를 처음 사진이 적용되었을 때와 같은 결과를 만들어보자.








내가 변경한 ORIENTATION 정보에 맞추어서 강제로 변경을 해보는 것이다.





# 소스코드

<html>
<head>
<title>:: JavaScript 이미지 EXIF 정보 추출 ::</title>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/exif-js"></script>

<script type="text/javascript">
    function uploadImgPreview() {

        // @breif 업로드 파일 읽기
        const fileInfo = document.getElementById( "upImgFile" ).files[0];
        const reader = new FileReader();

        // @details readAsDataURL( )을 통해 파일을 읽어 들일때 onload가 실행
        reader.onload = function() {

            console.log( reader.result );
            document.getElementById( "thumbnailImg" ).src = reader.result;

            EXIF.getData( fileInfo, () => {

                const orientation = EXIF.getTag( fileInfo, "Orientation" );
                console.log( orientation );

                switch( orientation ) {

                    // @details 이미지 회전값이 0인경우 ( 정방향 )
                    case 1 :
                        document.getElementById( "thumbnailImg" ).style.transform = "rotate( 0deg )";
                        break;

                    // @details 이미지 회전값이 180 기운 경우
                    case 3 :
                        document.getElementById( "thumbnailImg" ).style.transform = "rotate( 180deg )";
                        break;

                    // @details 이미지 회전값이 270 기운 경우 ( 왼쪽으로 90 기운 경우 )
                    case 6 :
                        document.getElementById( "thumbnailImg" ).style.transform = "rotate( 90deg )";
                        break;

                    // @details 이미지 회전값이 90 기운 경우
                    case 8 :
                        document.getElementById( "thumbnailImg" ).style.transform = "rotate( 270deg )";
                        break;
                }
            });
        };

        if( fileInfo ) {


            // @details readAsDataURL( )을 통해 파일의 URL을 읽어온다.
            reader.readAsDataURL( fileInfo );
        }
    }
</script>
</head>
<body>
    <!-- @breif accept 태그는 파일 업로드시 그것을 이미지 파일로 제한한다. -->
    <input type="file" id="upImgFile" onChange="uploadImgPreview();" accept="image/*">
    <h3># EXIF - Orientation 값 적용 </h3>
    <hr/>
    <img id="thumbnailImg" src="" style="width:100%;height:auto;">
    <hr/>
    <h3># 다이렉트로 띄우기</h3>
    <img src="./DSC_IMG.jpg" style="width:100%;height:auto;">
</body>
</html>





# 출력결과









Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] 이미지 파일 업로드하고 썸네일 생성하기[JavaScript] 이미지 파일 업로드하고 썸네일 생성하기

Posted at 2020. 3. 25. 18:35 | Posted in JavaScript & jQuery/JavaScript




참고 : https://developer.mozilla.org/ko/docs/Web/API/FileReader

참고 : https://developer.mozilla.org/ko/docs/Web/API/FileList

참고 : https://developer.mozilla.org/ko/docs/Web/API/FileReader/readAsDataURL

참고 : https://developer.mozilla.org/ko/docs/Web/HTTP/Basics_of_HTTP/MIME_types





■ FileReader 메소드




속성

설 명

 FileReader.error

 · DOMError 파일을 읽는 도중에 발생한 에러를 나타낸다.

 FileReader.readyState

 · FileReader의 상태를 나타내는 숫자

   ① EMPTY : 0  ( 아직 데이터가 로드 되지 않았음 )

   ② Loading : 1 ( 데이터가 로딩 중 )

   ③ DONE : 2 ( 모든 읽기 요청이 완료됨 )

 FileReader.result

 · 파일의 컨텐츠

 · result 속성은 읽기 작업이 완료되고 읽기 작업의 초기화에 사용한 방식으로 결정된

  데이터의 포맷이 정해진 후에 유효하다.

 FileReader.onabort

 · onabort 이벤트는 읽기 동작이 중단 될 때마다 발생한다.

 · abort 이벤트의 핸들러

 FileReader.onerror

 · onerror 이벤트는 읽기 동작에 에러가 생길 때마다 발생한다.

 · error 이벤트이 핸들러

 FileReader.onload

 · onload 이벤트는 읽기 동작이 성공적으로 완료 되었을 때마다 발생한다.

 · load 이벤트 핸들러

 FileReader.onloadstart

 · onloadstart 이벤트는 읽기 동작이 실행 될 때마다 발생한다.

 · loadstart 이벤트 핸들러

 FileReader.onloadend

 · onloadend 이벤트는 읽기 동작이 끝났을 때마다 발생한다.( 읽기의 성공 이나 실패 여부는 상관 없다. )

 · loadend 이벤트 핸들러

 FileReader.onprogress

 · onprogress 이벤트는 Blob 컨테트를 읽는 동안 호출된다.

 · progress 이벤트 핸들러



※ Blob란?


Blob 객체는 파일류의 불변하는 미가공 데이터를 나타낸다.

텍스트와 이진 데이터 형태로 읽을 수 있으며, ReadableStream으로 변환한 후 그 메서드를 사용 데이터를 처리할 수 도 있다.


Blob은 JavaScript 네이티브 형태가 아닌 데이터도 표현할 수 있다.

File 인터페이스는 사용자 시스템의 파일을 지원하기 위해 Blob 인터페이스를 확장한 것이므로, 모든 블롭 기능을 상속한다.









■ 이미지 파일 업로드하고 썸네일 출력하기





# 소스코드

<html>

<head>

<title>:: JavaScript 파일 썸네일 추출 ::</title>

<script type="text/javascript">

    function uploadImgPreview() {


    // @breif 업로드 파일 읽기

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

    let reader = new FileReader();

        // @details readAsDataURL( )을 통해 파일을 읽어 들일때 onload가 실행

        reader.onload = function() {

       

            // @details 파일의 URL을 Base64 형태로 가져온다.

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

            document.getElementById("thumbnailUrl").innerText = reader.result;

        };


        // @details onload 대신 addEventListener( ) 사용가능

    // reader.addEventListener("load", function() {

        //    document.getElementById("thumbnailImg").src = reader.result;

        //    document.getElementById("thumbnailUrl").innerText = reader.result;

    // }, false);

    if( fileInfo ) {

   

            // @details readAsDataURL( )을 통해 파일의 URL을 읽어온다.

            reader.readAsDataURL( fileInfo );

        }

    }

</script>

</head>

<body>

    <!-- @breif accept 태그는 파일 업로드시 그것을 이미지 파일로 제한한다. -->

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

    <hr/>

    <img id="thumbnailImg" src="">

    <br/>

    <div id="thumbnailUrl"></div>

</body>

</html> 





# 출력결과











■ 여러장의 이미지 업로드하고 화면에 나타내기





# 소스코드

<html>

<head>

<title>:: JavaScript 파일 썸네일 추출 ::</title>

<script type="text/javascript">

    function uploadImgPreview() {


    // @breif 업로드 파일 읽기

    let fileList = document.getElementById( "upImgFiles" ).files;


// @breif 업로드 파일 읽기

function readAndPreview( fileList ) {


// @breif 이미지 확장자 검사

if ( /\.(jpe?g|png|gif)$/i.test( fileList.name ) ) {


let reader = new FileReader();


reader.addEventListener( "load", function() {


let image = new Image();


image.width = "264";

image.height = "264";

image.title = fileList.name;

image.src = this.result;


// @details 이미지 확장자 검사

document.getElementById( "thumbnailImgs" ).appendChild( image );


}, false );


// @details readAsDataURL( )을 통해 파일의 URL을 읽어온다.

if( fileList ) {

reader.readAsDataURL( fileList );

}

}

}


    if( fileList ) {


                // @details readAndPreview() 함수를 forEach문을통한 반복 수행

[].forEach.call( fileList, readAndPreview );

        }

    }

</script>

</head>

<body>

    <!-- @breif accept 태그는 파일 업로드시 그것을 이미지 파일로 제한한다. -->

    <input type="file" id="upImgFiles" onChange="uploadImgPreview();" accept="image/*" multiple>

    <hr/>

    <div id="thumbnailImgs"></div>

</body>

</html> 





# 출력결과






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

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

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

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






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 | 비밀글로 남기기

[JavaScript] Canvas를 통한 이미지 회전[JavaScript] Canvas를 통한 이미지 회전

Posted at 2020. 3. 4. 11:06 | Posted in JavaScript & jQuery/JavaScript




■ 휴대폰 사진 업로드시 이미지가 가로, 세로가 변경되는 이유





휴대폰, 스마트폰의 카메라로 찍은 사진을 웹 브라우저를 통해 업로드 할경우,


이미지의 가로, 세로가 변경되어 등록되는 경우가 존재한다.


이러한 이유는 EXIF( Exchangeable Image File Format ) 의


회전값 변경이 반영되지 않기에 생기는 이유인데.



아래 이미지는 초기 스마트 폰에서 자주 볼 수 있었던 문제이다.

( 자이로 센서( Gyro Sensor ) 등의 기술 발전으로 이런 문제는 많이 해결 되었지만, 이미지의 편집등 다른 작업 과정으로 현재에도 이런 문제를 맏닥드릴 수 있다. )









가로로 찍은 이미지의 경우 스마트폰 상에서는 분명 정상적으로 보여주지만.


실제 이미지의 EXIF 값을 보면 회전정보( Orientation )가 90° CW 가 적용되어 있는것을 알 수 있다.


이를 회전정보 값을 브라우저에서는 인식하지 않고 보여지는 문제이다.







   # EXIF( Exchangeable Image File Format ) 란?



   디지털 카메라 등에서 사용되는 이미지 파일 메타데이터 포맷으로,


   카메라가 촬영한 사진, 녹음파일에 시간 등의 각종 정보를 담기 위해 개발되었다. 즉, 


   JPEG, TIFF 6.0과 RIFF, WAV 포맷에 이미지나 소리에 대한 정보를 추가로 기록할 수 있다.


   디지털카메라의 보급으로 널리 활성화되었고 이미지 메타데이터의 사실상 표준 지위에 있다.


   EXIF 데이터는 이미지 파일의 일부로 저장되며,


   EXIF 데이터를 지원하는 소프트웨어 사용 시 이미지를 변경해도 데이터를 보존한다.



   출처 : 나무위키( https://namu.wiki/w/EXIF )






간단하게 이미지 파일 하나를 선택하여 마우스 오른쪽 버튼을 클릭하고


오른쪽으로 회전( T ) 을 선택해 보자.





회전 정보 : 90° CW 로 반영된 것을 확인할 수 있다.


이 렇게 회전된 파일을 <img src="스토브리그.jpg">로 올려서 브라우저로 확인을 해 본다면.



# 소스코드

<html>

<head>

<title>:: 스토브리그 ::</title>

<style type="text/css">

/* image-orientation:from-image; */

</style>

</head>

<body>

<img src="stoveleague.jpg"/>

</body>

</html> 



# 출력결과




회전 정보 : 90° CW가 반영이 <img> 태그를 사용한 경우


브라우저에서 다시 정방향으로 돌려서 출력하는 모습을 확인 할 수 있다.




현재 파이어 폭스 브라우저의경우 CSS에 image-orientation:from-image; 를 넣어주는 것만으로도


회전정보 값을 읽어들여 반영하여 이미지가 돌아가는 것을 막아주어서 해결할 수 있지만.


아직까지 크롬등의 다른 브라우저에서는 CSS4의 실험적 기능이기에 적용되어 있지 않다고 한다.


결국 자동으로 이러한 상황을 해결 할 수는 없는 상황이기에


사용자의 폰, 찍은 각도에 따라 업로드시 문제가 발생할 수 있다.











■ 캔버스를 통한 업로드 이미지 각도 조정




그래서 필자는 이에대한 해결책으로


자동으로 이미지를 보정하는 것이 아닌,


사용자가 직접 수동으로 이미지를 수정하는 방향으로 가닥을 잡고,


다 완성된 정보만을 서버로 전달하는 형태로 취하는 방식을 택하게 되었다.




# 소스코드

<html>

<head>

<title>:: JavaScript 캔버스 - 회전 ::</title>

<script type="text/javascript">


    function uploadImgPreview() {


     // @breif 업로드 파일 읽기

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

     let reader = new FileReader();


     reader.addEventListener("load", function() {


          console.log("INDEX #02");


          // @details 업로드한 파일의 URL을 가져온다.

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


     }, false);


     if(fileInfo) {


          console.log("INDEX #01");


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

          reader.readAsDataURL(fileInfo);

        }

    }


    function rotateCanvasImg( angle ) {


     // @breif 썸네일 이미지 생성

    let tempImage = new Image();                         // @details drawImage 메서드에 넣기 위해 이미지 객체화

        tempImage.src = document.getElementById("thumbnail").src; // @details 업로드 완료된 이미지를 객체에 주입


     tempImage.onload = function() {


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

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

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


          // @breif 왼쪽( 270° ) 회전의 경우

          if( angle == '270' ) {


               // @details 270° 회전의 경우 이미지의 높이와 넓이를 서로 바꿔준다.

               canvas.width = tempImage.height;

canvas.height = tempImage.width;


               canvasContext.rotate((270) * Math.PI / 180);


               // @details 이미지가 270° 회전 했을 경우 x축의 값을 업로드 이미지의 넓이를 음수로 변경한다.

               canvasContext.drawImage(this, (tempImage.width * -1), 0);


          }


// @breif 오른쪽( 90° ) 회전의 경우

          else if( angle == '90' ) {


               // @details 90° 회전의 경우 이미지의 높이와 넓이를 서로 바꿔준다.

               canvas.width = tempImage.height;

canvas.height = tempImage.width;


               // canvasContext.rotate((90) * Math.PI / 180);

               canvasContext.rotate(Math.PI / 2);


               // @details 이미지가 90° 회전 했을 경우 y축의 값을 업로드 이미지의 높이 음수로 변경한다.

canvasContext.drawImage(this, 0, (tempImage.height * -1));


          }


          // @breif 거꾸로( 180° ) 회전의 경우

          else if( angle == '180' ) {


               canvas.width = tempImage.width;

               canvas.height = tempImage.height;


               // canvasContext.rotate((180) * Math.PI / 180);

               canvasContext.rotate(Math.PI);


               // @details 이미지가 180° 회전 했을 경우 x, y축의 값을 업로드 이미지의 넓이와 높이 음수로 변경한다.

               canvasContext.drawImage(this, (tempImage.width * -1), (tempImage.height * -1));


          }


          // @breif 정방향

          else {


               canvas.width = tempImage.width;

               canvas.height = tempImage.height;

               canvasContext.drawImage(this, 0, 0);

          }


          // @breif 캔버스의 이미지

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

          document.querySelector("#thumbnail").src = dataURI;


     };

    }

</script>

</head>

<body>

    <!-- @breif accept 태그는 파일 업로드시 그것을 이미지 파일로 제한한다. -->

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

    &nbsp;|&nbsp;

    <input type="button" onClick="rotateCanvasImg('270');" value="왼쪽(270°)"/>

    &nbsp;|&nbsp;

    <input type="button" onClick="rotateCanvasImg('90');" value="오른쪽(90°)"/>

    &nbsp;|&nbsp;

    <input type="button" onClick="rotateCanvasImg('180');" value="거꾸로(180°)"/>

    &nbsp;|&nbsp;

    <input type="button" onClick="uploadImgPreview();" value="되돌리기"/>

    <hr/>

    <img id="thumbnail" src="">

    <!-- @breif 캔버스는 화면에 노출시키지 않는다. -->

    <canvas id="canvas" style="display:none;"></canvas>

</body>

</html>




# 출력결과




이렇게 이미지 조작이 완료되었다면.


해당 미지를 마우스 우클릭으로 다운받아 보자.








다운받은 이미지는 index.jpg 라는 이름으로 생성되며


회전 정보가 표기되지 않는 0° CW 임을 알 수 있다.


그렇기에 해당 이미지를 <img> TAG를 사용해도 원하는 각도 조절이 가능하기에




사용자의 업로드한 사진의 이미지 축 보정 작업이 끝나고 사진 등록( 파일 업로드 )을 실행하면


편집된 캔버스의 작업내용을 서버에 전송하는 형태로 진행을 하면 된다.






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

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

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

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







  1. 비밀댓글입니다

Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] 업로드한 파일 Resizer 하여 화면에 출력시키기[JavaScript] 업로드한 파일 Resizer 하여 화면에 출력시키기

Posted at 2020. 3. 4. 07:34 | Posted in JavaScript & jQuery/JavaScript




업로드한 파일 리사이즈 하여 화면에 출력시키기




<html>

<head>

<title>:: JavaScript 캔버스 - 뷰 ::</title>

<style type="text/css">

table {

            border:1px solid #444444;

            border-collapse:collapse;

  }

table th {

            border:1px solid #444444;

            padding:5px 10px 5px 10px;

            text-align:center;

            font-weight:bold;

}

table td {

            border:1px solid #444444;

            padding:10px;

            text-align:center;

  }

</style>

<script type="text/javascript">


    function uploadImgPreview() {


        // @breif 업로드 파일 읽기

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

        let reader = new FileReader();


        // @details INDEX #01 실행 이후, 파일의 업로드( onload )가 확인되고 나서 실행된다.

        reader.onload = function() {


            console.log( "INDEX #02" );


            // @details 업로드한 파일의 URL을 가져온다.

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


            // @breif 썸네일 이미지 생성

            let tempImage = new Image();    // @details drawImage 메서드에 넣기 위해 이미지 객체화

            tempImage.src = reader.result;    // @details data-uri를 이미지 객체에 주입


            tempImage.addEventListener("load", function() {


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

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

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

                // @breif 캔버스 크기 셋팅

                canvas.width = 240;

                canvas.height = 300;

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

                canvasContext.drawImage(

                  this // @details 업로드한 이미지 파일의 정보

                , -10 // @details X좌표

                , -10 // @details Y좌표

                , 270 // @details 넣을 이미지의 가로 사이즈( 해당 예제는 변화를 보기위해 살짝 크게 다. )

                , 330 // @details 넣을 이미지의 세로 사이즈( 해당 예제는 변화를 보기위해 살짝 크게 했다. )

                );

                

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

                canvasContext.stroke();

                

                // @breif 캔버스의 이미지 URL 정보를 받아 썸네일 출력

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

                document.querySelector("#thumbnail").src = dataURI;

            });

        };


        if( fileInfo) {


            console.log( "INDEX #01" );


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

            reader.readAsDataURL(fileInfo);

        }

    }


</script>

</head>

<body>

     <!-- @breif accept 태그는 파일 업로드시 그것을 이미지 파일로 제한한다. -->

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

    <hr/>

    <table>

<tr>

<th>업로드 이미지 출력</th>

<th>이미지 캔버스 출력</th>

</tr>

<tr>

<td rowspan="3"><img id="preview" src=""></td>

<td><canvas id="canvas"></canvas></td>

</tr>

<tr>

<th>캔버스 이미지 변환</th>

</tr>

<tr>

<td><img id="thumbnail" src=""></td>

</tr>

    </table>

</body>

</html> 







① 이미지 파일을 업로드 한다.


② 업로드한 이미지를 화면에 출력한다.


③ 지정한 캔버스 영역에 해당 이미지를 그대로 리사이징 하여 따라 그리는 작업을 수행한다.

    ( 이때 기본적으로 이미지는 *.png 파일로 생성된다. )


④ 마지막으로 캔버스의 이미지 파일을 그대로 다시 이미지로 출력시키는 작업을 수행한다.







사실 필자가 해당 글을 작성하게 된 경위는


[JavaScript] Canvas를 통한 이미지 회전 포스팅의 사전 준비 과정이었다.


캔버스를 통해 프론트 개발의 좀더 넓은 시각을 바라보고.


HTML5의 가능성에 대해서 좀더 알아봐야 겠다는 생각을 하고 있다.











Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[jQuery] load( ) 메소드를 이용한 외부 데이터의 페이지 반영[jQuery] load( ) 메소드를 이용한 외부 데이터의 페이지 반영

Posted at 2020. 3. 2. 19:03 | Posted in JavaScript & jQuery/jQuery



■ 새로고침 없이변경된 데이터 조회하기




Ajax 통신을 사용한 비동기 통신으로


웹 브라우저의 새로고침 없이 데이터를 조회하거나, 변경 및 이벤트를 실행하는 경우는 많이 보아 왔을 것이다.


또한 iframe을 통해 작업되어져 있는 다른 페이지의 정보를 가져오는 방식으로도


새로고침 없이 작업을 진행 할 수 있지만.



여기서 설명할 .load( ) 메소드는 Ajax와 iframe은 비슷한 기능을 수행하면서도, 좀 하위 호한의 느낌이 강하지만.


사용여부와 방법에따라서 직관적이고 단순한 사용의 장점이 있다.


단순히 가져올 데이터가 명확하다면 .load( ) 메소드는 큰 힘을 발휘 하게 된다.



 load_front.php

<html>

<head>

<title>:: jQuery load() 함수 ::</title>

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

<script type="text/javascript">

jQuery(document).ready(function() {

backLoadAgainCall();

});


function backLoadAgainCall() {

jQuery(".output").load("load_back.php");

}

</script>

</head>

<body>

<input type="button" onClick="backLoadAgainCall();" value="재호출">

<hr/>

<div class="output"></div>

</body>

</html>




 load_back.php

<html>

<head>

<title>:: jQuery load() 함수 ::</title>

<style type="text/css">

#turnImg { transform:rotate(0deg); }

/* #turnImg { transform:rotate(90deg); } */

/* #turnImg { transform:rotate(180deg); } */

/* #turnImg { transform:rotate(270deg); } */

</style>

</head>

<body>

<img id="turnImg" src="joker.jpg"/>

</body>

</html>




코드를 다 작성했다면.


load_front.php 를 실행한다.


이후 load_back.php에서 #turnImg { transform : rotate ( 0deg ); } 를 


0 → 90 → 180 → 270 순서로 한번씩 변경하면서


브라우저의 재호출 버튼을 클릭해 보자.






load_front.php를 새로고침 하지 않고 load_back.php의 변경된 사항을 반영하여


이미지가 계속 회전하는 것을 확인 할 수 있다.


위와같이 jQuery의 .load( ) 를 사용하면


이미 만들어진 결과를 페이지의 새로고침 없이 가져올 수 있어.


경우의 따라서는 Ajax 호출과 구분하여 사용할 수 있다.













Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기

[JavaScript] getElementByTagName( ) 메소드[JavaScript] getElementByTagName( ) 메소드

Posted at 2020. 2. 28. 13:54 | Posted in JavaScript & jQuery/JavaScript




발췌 : 하루 10분씩 핵심만 골라 마스터하는 Ajax





■ documet.getElementByTagName( ) 메소드





getElementByTagName( ) 메소드를 이용하면 각각의 태그 명을 통해서


문서안의 요소들에 대해서 자바스크립트 배열을 만들 수 있다.


자바스크립트 코드에서 다음과 같이 문서 안의 요소에 접근을 할 수 있다.




# 소스코드

<html>

<head>

<title>:: JavaScript - getElementsByTagName ::</title>

<script type="text/javascript">

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


        const txtElements = document.getElementsByTagName("input")[0].value;

        alert( txtElements );


    });

</script>

</head>

<body>

    <input type="text" value="누구나 그럴싸한 계획을 갖고 있다.\n치명타에 세 번 연속으로 처맞기 전까지는. 으하하하하하하하"/>

</body>

</html>




# 출력결과









이 코드는 block 이라는 태그 이름을 가진 모든 요소들을 blocks 라는 변수에 배열 형식으로 반환하는 코드이다.


다음 코드처럼 다른 일반 배열과 같은 방식으로 배열의 크기를 알 수 있다.

( 인자로 주어진 태그 이름과 같은 요소들의 개수를 의미한다. )



# 소스코드

<html>

<head>

<title>:: JavaScript - getElementsByTagName ::</title>

<script type="text/javascript">

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


        const blocks = document.getElementsByTagName( "block" );

        alert( blocks.length );


    });

</script>

</head>

<body>

    <block>1번 블럭</block>

    <block>2번 블럭</block>

    <block>3번 블럭</block>

    <block>4번 블럭</block>

    <block>5번 블럭</block>

    <block>6번 블럭</block>

    <block>7번 블럭</block>

</body>

</html>




# 출력결과










배열의 각각의 요소에 대해서도 접근할 수 있다.


bean이라는 이름을 가진 두 번째 요소에 대해서 접근할 경우


bean[1]로 접근이 가능하다.




# 소스코드

<html>

<head>

<title>:: JavaScript - getElementsByTagName ::</title>

<script type="text/javascript">

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


        const bean = document.getElementsByTagName("bean")[1];

        alert( bean.innerHTML );


    });

</script>

</head>

<body>

    <bean>임요환</bean>

    <bean>홍진호</bean>

    <bean>강   민</bean>

</body>

</html> 




# 출력결과







Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기