반응형

https://myhappyman.tistory.com/93

 

HTML, JAVASCRIPT - 테트리스 만들기 - 2

https://myhappyman.tistory.com/92 HTML, JAVASCRIPT - 테트리스 만들기 - 1(table요소, 배열값으로 테트리스 만들기) 웹 개발을 해보겠다고 예전에 학원을 다니면서 강사님과 같이 만들어봤던, 테트리스 예제가..

myhappyman.tistory.com

2장 이후 3장까지 왔습니다. 이번에는 키 이벤트를 처리해보겠습니다.

 

3. 키 이벤트에 따라 테트리스 제어하기

이번에는 키 이벤트를 받아서 테트리스를 제어해보겠습니다.

 

2장에서 만들었던 action 메소드에 keypress 이벤트를 추가하겠습니다.

keypress 처리

function action(){
    //keyEvent
    document.addEventListener("keypress", function(){
        myFunction(event.keyCode);
    });
}

특정 키값을 받을때마다 파라미터 값으로 myFunction에 파라미터로 넘겨주고 그에 따라 동작을 정의할 것입니다.

 

myFunction - 입력값에 따른 출력 메시지

function myFunction(input){
    switch(input){
        case 53://회전
            console.log("5번이 입력되었습니다.");
            break;
        case 49://블럭왼쪽이동                        
            console.log("1번이 입력되었습니다.");
            break;
        case 51://블럭오른쪽이동            
            console.log("3번이 입력되었습니다.");
            break;
        case 50://블럭아래로이동            
            console.log("2번이 입력되었습니다.");
            break;
        case 32://스페이스
            console.log("스페이스바가 입력되었습니다!");
            break;
    }
    //테트리스 블럭 그리기
    drawTetris(GX, TYPE, TURN);
}

 

action 함수에서 키이벤트를 추가했기 때문에 키보드 입력값이 들어오면 myFunction이 실행될텐데 이제 파라미터 input값에 따라 switch문에서 동작을 시켜줄겁니다.

저는 우측 키보드로 게임을 즐긴다고 생각하고 키 세팅을 했는데, 이 부분은 원하시는 키값으로 하시면 됩니다.

키 세팅

 

키 입력을 정상적으로 받아진다.

실행 후 키보드를 입력해보면 블럭은 움직이지 않지만 키보드 입력에 따라 콘솔로그값이 찍히는 모습을 볼 수 있습니다.

 

이제 입력값에 따라 실제로 이동이 되거나 블록을 회전시키거나 맨 아래로 이동시켜야겠죠?

바로 동작을 처리해보겠습니다.

회전, 스페이스바, 이동 시키기

function myFunction(ChangeValue){
    switch(ChangeValue){
        case 53://회전
            TURN++;
            TURN = TURN % 4;
            break;
        case 49://블럭왼쪽이동
            GY--;
            break;
        case 51://블럭오른쪽이동
            GY++;
            break;
        case 50://블럭아래로이동            
            GX++;
            break;
        case 32://스페이스
            GX=21;
            break;
    }
    //테트리스 블럭 그리기
    drawTetris(GX, TYPE, TURN);
}

53은 윗 방향을 누르는 키값으로 회전이 되어야 합니다. 즉, TURN의 값을 증가시키고 그리면 됩니다.

하지만 %연산자가 있는것을 볼 수 있는데, 존재하는 이유는 회전은 4가지의 모습이 있기 때문입니다.

 

맨 처음 시작할때 추가하였던 tetris_data.js에서 TETRIS 변수 중 ㄹ모양의 블럭을 예시로 볼 경우

ㄹ 모양 4가지 회전

이렇게 4가지 형태를 볼 수 있습니다.

이러한 이유때문에 모든 블럭을 4가지 형태로 넣었고, ㅁ모양의 블럭도 4가지인 이유입니다.

 

실행해서 해보면 일정시간마다 블럭이 내려가게 했을 때처럼 이전 블럭의 잔상이 남는 것을 볼 수 있는데, 눈치채신분들은 여기서 지우는 함수를 넣으면 된다는것을 알 수 있을겁니다.

키 이벤트에 따라 변경되지만 잔상이 남는다.

 

erase함수를 역시 처음에 추가해보겠습니다.

 

그럴싸한 myFunction - erase함수까지 추가

function myFunction(input){
    //그리기 전에 지우기 추가!!!
    erase(GX, TYPE, TURN);
    switch(input){
        case 53://회전
            TURN++;
            TURN = TURN % 4;
            break;
        case 49://블럭왼쪽이동
            GY--;
            break;
        case 51://블럭오른쪽이동
            GY++;
            break;
        case 50://블럭아래로이동            
            GX++;
            break;
        case 32://스페이스
            GX=21;
            break;
    }
    //테트리스 블럭 그리기
    drawTetris(GX, TYPE, TURN);
}

 

아직 완벽하진 않지만 그럴싸하게 키 이벤트도 받고 동작이 되는 모습을 볼 수 있습니다.

 

 

다음 포스팅에서는 마지막행에 닿으면 현재 블럭의 이벤트가 멈추고 다음블럭으로 넘어갈 수 있게 추가해보겠습니다.

 

반응형
반응형

https://myhappyman.tistory.com/92

 

HTML, JAVASCRIPT - 테트리스 만들기 - 1(table요소, 배열값으로 테트리스 만들기)

웹 개발을 해보겠다고 예전에 학원을 다니면서 강사님과 같이 만들어봤던, 테트리스 예제가 있어서 약간의 소스 정리 후 포스팅을 하면 좋을 것 같아 테트리스 만들기 예제를 시작합니다. 테트리스 만들기 예제들..

myhappyman.tistory.com

 

테트리스 만들기 1장 이후 2장입니다.

 

테트리스 구조를 만들고 맵을 만들었으니 이제 테트리스 다운 동작을 만들어야 할 것같습니다.

 

이번엔 index.js에 action()이라는 함수를 추가해서 일정 시간마다 자연스럽게 내려가는 동작을 추가해보겠습니다.

여기서 일정시간마다 동작한다. 라는 부분에서 떠오르는 함수가 있으신가요? setInterval 또는 setTimeout, animationFrame등이 생각 날 것 같습니다. 저는 setInterval을 활용해서 처음에 정의한 gamespeed의 변수값마다 동작하도록 작성했습니다.

 

2. 일정시간마다 블럭이 떨어지는 효과 만들기

index.js - action()

window.onload = function(){
    drawMap();
    drawNextTetris(Ntype);
    myFunction();
    action(); //action 함수 추가
}

/**
 * 동작 메소드
 * interval 함수로 입력시간마다 동작
 * (gameSpeed에 따라 떨어지는 속도가 변경)
 */
function action(){

    var intervalID = setInterval(function(){
        console.log("action!")
        GX++;
        drawTetris(GX, TYPE, TURN);
    }, GAME_SPEED);
}

window.onload 맨 끝에 action함수를 추가하여 페이지가 로드되면 action함수가 실행되도록 처리하였습니다.

 

action 함수 내부를 보니 Interval함수에 의해 GAME_SPEED값마다 콘솔로그값을 출력 후 GX전역 변수값을 증가시킨 후에 drawTetris 함수를 호출하는 것을 볼 수 있습니다.

 

 

drawTetris함수는 현재 선택된 테트리스의 값을 특정 위치에 그려주는 함수 입니다.

특정 위치를 그려주므로 일정 시간마다 우리는 위에서 아래로 떨어지는 모습을 위해 GX변수값을 증가시켜주면 자연스럽게 밑으로 계속해서 그려줄 것입니다.

 

 

 

하지만 계속 그려주게되면 이전 모습이 남아있어 이러한 형태로 잔상이 있겠죠?

이제 잔상을 지워주는 함수를 만들겠습니다.

 

 

erase 함수

한줄씩 내리면서 특정위치를 지우기전에 현재 위치의 테트리스 블럭값을 확인하고 지우는 erase 함수를 만들어보겠습니다.

//특정 지역을 map으로 초기화 (block값으로 되어있던걸 map으로)
function erase(GX, TYPE, TURN){
    for(var x=0; x<TETRIS[BLOCKTYPE][BLOCKROTATE].length; x++){
        for(var y=0; y<TETRIS[BLOCKTYPE][BLOCKROTATE][x].length; y++){
            if(TETRIS[TYPE][TURN][x][y]==1){
                ChangeColor(x+GX, y+GY, "map");
            }
        }
    }
}

function action(){
    var intervalID = setInterval(function(){
        erase(GX, TYPE, TURN); //생성한 전위치 블럭 삭제
        GX++; //한줄씩 내리기
        drawTetris(GX, TYPE, TURN); //테트리스를 그린다.
    }, GAME_SPEED);
}

 

현재의 테트리스 모양과 회전위치값을 가지고 와서 1이면 블럭모양이므로 1인지 체크 후에 블럭모양이라면 erase함수에서는 map이라는 클래스를 넣어 모두 맵으로 바꿔줍니다.

 

그럼 아래와 같이 지우면서 그리기 때문에 테트리스처럼 보이게 되죠.

 

지우면서 그려진다.

반응형
반응형

웹 개발을 해보겠다고 예전에 학원을 다니면서 강사님과 같이 만들어봤던, 테트리스 예제가 있어서 약간의 소스 정리 후 포스팅을 하면 좋을 것 같아 테트리스 만들기 예제를 시작합니다.

 

테트리스 만들기 예제들을 찾아보면 캔버스값으로 처리하는 예제들이 많던데, 아직 캔버스 사용이 쉽지는 않은터라 게임치고는 UI가 엄청 화려하게 변화는 없는 테트리스정도는 html의 간단한 요소들로 충분히 표현이 가능하고 jquery나 다른 화려한 플러그인 없이 순수 javascript만으로 로직을 구성해서 표현할 수 있는 테트리스를 선택하게 되었습니다.

크게 구분하자면 배열데이터를 조작하고 매번 배열의 데이터를 검사하여 table요소를 통해 UI를 표현하는 형태로 진행할 예정입니다.

 

 

 


1. 작성을 위해 페이지 구성 & 배열 데이터 만들기 맵 그리기

 

페이지별 구성도

이러한 형태로 페이지들을 구성할 예정입니다.

메인이될 index.html 페이지

css를 꾸며줄 index.css

동작처리를 위한 index.js

전체 맵데이터, 테트리스 모양데이터를 담아놓을 tetris_data.js 로 구성하여 소스를 작성하겠습니다.

 

각각 소스들을 보도록 하겠습니다.

 

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="./css/index.css">
    <title>Tetris</title>
    <script src="./js/tetris_data.js"></script>
    <script src="./js/index.js"></script>
</head>
<body>
    <div id="container"></div>
</body>
</html>

사용할 index.html은 1개입니다.

tetris_data.js라는곳에는 전역으로 처리할 맵 배열과 테트리스 모양배열을 담아두고 실질적으로 돌아가는 코드 동작은 index.js에서 처리할 예정입니다.

 

tetris_data.js

//맵
var MAP=[
    [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4],       
    [4,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,2,2,2,2,2,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,2,2,2,2,2,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,2,2,2,2,2,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,2,2,2,2,2,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,2,2,2,2,2,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,0,0,0,0,0,0,0,0,0,0,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4],
    [4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4]];

//테트리스 조각
var TETRIS=[
    [
        [//막대기
            [0,0,0,0],
            [1,1,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,0,0],
            [0,1,0,0],
            [0,1,0,0],
            [0,1,0,0]
        ],
        [
            [0,0,0,0],
            [1,1,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,0,0],
            [0,1,0,0],
            [0,1,0,0],
            [0,1,0,0]
        ]
    ],
    [
        [//ㄹ1
            [0,1,0,0],
            [0,1,1,0],
            [0,0,1,0],
            [0,0,0,0]
        ],
        [
            [0,0,1,1],
            [0,1,1,0],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,0,0],
            [0,1,1,0],
            [0,0,1,0],
            [0,0,0,0]
        ],
        [
            [0,0,1,1],
            [0,1,1,0],
            [0,0,0,0],
            [0,0,0,0]
        ]
    ],
    [
        [//ㄹ2
            [0,0,1,0],
            [0,1,1,0],
            [0,1,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,0],
            [0,0,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,0,1,0],
            [0,1,1,0],
            [0,1,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,0],
            [0,0,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ]
    ],
    [
        [//ㄱ
            [0,1,1,0],
            [0,0,1,0],
            [0,0,1,0],
            [0,0,0,0]
        ],
        [
            [0,0,0,1],
            [0,1,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,0,0],
            [0,1,0,0],
            [0,1,1,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,1],
            [0,1,0,0],
            [0,0,0,0],
            [0,0,0,0]
        ]
    ],
    [
        [//ㄴ
            [0,1,1,0],
            [0,1,0,0],
            [0,1,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,0,0],
            [0,1,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,0,1,0],
            [0,0,1,0],
            [0,1,1,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,1],
            [0,0,0,1],
            [0,0,0,0],
            [0,0,0,0]
        ]
    ],
    [
        [//ㅁ
            [0,1,1,0],
            [0,1,1,0],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,0],
            [0,1,1,0],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,0],
            [0,1,1,0],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,1,1,0],
            [0,1,1,0],
            [0,0,0,0],
            [0,0,0,0]
        ]
    ],
    [
        [//ㅗ
            [0,0,1,0],
            [0,1,1,1],
            [0,0,0,0],
            [0,0,0,0]
        ],
        [
            [0,0,1,0],
            [0,0,1,1],
            [0,0,1,0],
            [0,0,0,0]
        ],
        [
            [0,0,0,0],
            [0,1,1,1],
            [0,0,1,0],
            [0,0,0,0]
        ],
        [
            [0,0,1,0],
            [0,1,1,0],
            [0,0,1,0],
            [0,0,0,0]
        ]
    ]
];

- 전역변수 MAP 배열에 테트리스 맵 데이터를 담아놓고 그릴 배열입니다.

  > 2차원 배열

  > 4의 값은 게임의 보드를 표현할 값입니다.

  > 3은 테트리스 가이드 라인으로 처리할 값입니다.

  > 2번은 다음 테트리스 블럭을 표현할 테트리스맵으로 검은 배경을 처리할 값입니다.

  > 0번은 테트리스 블럭이 돌아다니는 테트리스맵으로 검은 배경을 처리할 값입니다.

 

- 전역변수 TETRIS는 테트리스 게임의 블럭들을 담아놓는 배열입니다. ㅡ, ㄱ, ㄴ, ㄹ, ㅁ, ㅗ 형태의 블럭을 회전 4회의 모양별로 담아두었습니다.

  > 3차원 배열[첫번째][두번째][세번째]

  > 첫번째 인덱스의 값은 테트리스의 모양을 구분합니다.

  > 두번째 인덱스의 값은 테트리스의 회전을 구분합니다.

  > 세번째 인덱스의 값은 맵의값인지 블럭의값인지 구분합니다.

 

index.js

맵과 테트리스의 블럭들을 그려봐야겠죠?

실질적으로 동작을 정의할 자바스크립트입니다.

var GX = 0; //블럭을 생성할 초기 위치 X
var GY = 3; //블럭을 생서할 초기 위치 Y
var NGY = 17;
var TURN = 0;
var TYPE = Math.round(Math.random()*6);
var NTYPE = Math.round(Math.random()*6);
var BLOCKTYPE=6, BLOCKROTATE=3;
var GAME_SPEED = 2000;
 
window.onload = function(){
    drawMap();
    drawNextTetris(NTYPE);
    myFunction();
}

function drawMap(){
    var rowLen = MAP.length;
    var tag = "<table>";
    var x = 0;
    var y = 0;
    for(var i=0; i<rowLen; i++){
        tag += "<tr>"
        var colLen = MAP[i].length;
        for(var j=0; j<colLen; j++){
            var className = "";
            var idValue = "";
            if(MAP[i][j] == 0){
                className = "map";
                idValue = "x"+(i-2)+"y"+(j-2);
            }else if(MAP[i][j] == 2){
                className = "map";
                idValue = "xn"+(i-1)+"yn"+(j-16);
            }else if(MAP[i][j] == 3){
                className = "guard";
            }else if(MAP[i][j] == 4){
                className = "board";
            }

            if(idValue != ""){
                tag += "<td id="+idValue+" class="+className+"></td>"
            }else{
                tag += "<td class="+className+"></td>"
            }
            
        }
        tag += "</tr>"
    }
    document.getElementById("container").innerHTML = tag + "</table>";
};

function ChangeColor(x, y, cN){
    document.getElementById("x"+x+"y"+y).className = cN;
}

//다음에 그려질 방향의 테트리스 그리기
function drawNextTetris(NTYPE){
    for(var x=0; x<4; x++){
        for(var y=0; y<4; y++){
            if(TETRIS[NTYPE][0][x][y] == 1){
                ChangeColor("n"+(x+1), "n"+y, "block"+NTYPE);                
            }
        }
    }
}

//테트리스 그리기
function drawTetris(GX, TYPE, TURN){
    for(var x=0; x<TETRIS[BLOCKTYPE][BLOCKROTATE].length; x++){
        for(var y=0; y<TETRIS[BLOCKTYPE][BLOCKROTATE][x].length; y++){
            if(TETRIS[TYPE][TURN][x][y] == 1){
                ChangeColor(x+GX, y+GY, "block"+TYPE);
            }
        }
    }
}

//동작을 초기화하고 입력값에 따라 그려줄 함수
function myFunction(input){
    //테트리스 블럭 그리기
    drawTetris(GX, TYPE, TURN);
}

drawMap이라는 함수는 페이지가 로드되면 실행되면서 MAP배열의 값을 불러와서 table을 그리고 각각 td값에 알맞는 클래스값을 지정하여 테트리스 게임의 맵처럼 표출시키는 함수 입니다.

ChangeColor함수는 전달받은 x,y같에 따라 클래스명을 처리해줍니다.

drawNextTetris는 다음으로 그려질 블럭을 그리는 함수입니다.

drawTetris함수는 테트리스 블럭을 특정 위치에 그리는 함수 입니다.

myFunction은 현재 기능적으로 정의된게 없지만 추후에 동작 정의나 초기값 설정등을 처리할 함수입니다.

 

index.css

마지막으로 디자인을 입혀야 게임다운 느낌이 들겠죠? index.css입니다.

table{
    margin: auto;
    border-collapse: collapse;
}

td{
    width: 18px;
    height: 18px;
    text-align:center;
    vertical-align:middle;
    outline: 0.5px solid #EAEAEA;
}

.board{
    background-color: #5f3dc4;
}
.guard{
    background-color: #91a7ff;
}
.map{
    background-color: #495057;
}
.ghost{
    background-color: #495057;
}

.block0{
    background-color: #f5f100;
}
.block1{
    background-color: #e64980;
}
.block2{
    background-color: #ae3ec9;
}
.block3{
    background-color: #7048e8;
}
.block4{
    background-color: #4263eb;
}
.block5{
    background-color: #1098ad;
}
.block6{
    background-color: #37b24d;
}
.block7{
    background-color: #f59f00;
}

 

css까지 작성하시고 페이지를 열어보시면 이러한 기본 준비가 완성되어 있을겁니다.

 

 

다음장부터는 index.js에서 정의 동작을 수정하고 추가하면서 진행하다보면 어느새 완성된 테트리스를 만나볼 수 있을겁니다. 계속해서 진행해보겠습니다.

반응형
반응형

일정시간마다 기존에 그려진 차트 데이터에 추가되고 일정 데이터가 쌓이면 기존에 쌓였던 데이터는 지워지는 차트를 구현하게 되었는데 구글차트를 사용하게되어 포스팅을 진행합니다.

 

https://developers.google.com/chart

 

Charts  |  Google Developers

Interactive charts for browsers and mobile devices.

developers.google.com

 

해당 URL에서 데모차트들을 참조하여 시작하였습니다.

 

구글차트는 단순하게 입력하는 데이터의 배열값이 바뀌면 알아서 바뀌어서 처음에 구현할때는 chart의 data부분값을 배열로 따로 처리하여 넣고 빼고를 하였는데, 추가되는 데이터가 애니메이션 효과처럼 추가되는걸 표현하고 싶었고, 구글 차트 중 animation파트를 확인하면서 관련 예제를 기준으로 테스트버전을 만들었습니다.

 

https://developers.google.com/chart/interactive/docs/animation

 

Animation  |  Charts  |  Google Developers

This page describes how to animate modifications made to a chart, instead of applying them instantly. Contents Overview Google charts can animate smoothly in one of two ways, either on startup when you first draw the chart, or when you redraw a chart after

developers.google.com

 

해당 URL에서는 애니메이션이 동작하면서 차트가 그려지는 부분을 예제로 제공합니다.

 

 

세션중 Adding and removing rows 라는 부분이 있는데, 버튼 클릭에 따른 랜덤함수 값에 따른 비교 후 추가해주는 함수부분을 참고하여 만들었습니다.

 


아래는 사용한 테스트용 일정시간마다 데이터를 그리는 구글차트 자바스크립트 코드입니다. 

<html>
  <head>
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <style>
      .chart{
        border: 1px solid orange;
        float: left;
        margin: 30px;
      }
    </style>
  </head>
  <body>
    <div id="chart" class="chart" style="width: 779px; height: 300px"></div>
    <script type="text/javascript">
    //Google Stuff
    google.charts.load('current', {packages: ['corechart']});
    google.charts.setOnLoadCallback(function(){ drawChart(new_option)});
    </script>
    <script type="text/javascript">
      var chartOption = function(target, maxValue, color, name){
        this.name = name;
        this.target = target;
        this.data = null;
        this.chart = null;
        this.options = {
          legend: { position: 'none' },
          vAxis: {minValue:0, maxValue:maxValue},
          hAxis: {
            textStyle: {
              fontSize: 11
            }
          },
          colors: [color],
          animation: {
            duration: 500,
            easing: 'in',
            startup: true
          }
        }
        
      }

      var new_option = new chartOption('chart', 80, '#FF5E00', '온도');
      
      function drawChart(option) {
        var o = option;
        if(o != null){
          //초기값일때만 처리
          if(o.chart == null && o.data == null){
            o.data = new google.visualization.DataTable();
            o.data.addColumn('string', 'time');
            o.data.addColumn('number', o.name);
            o.data.addRow(['', 0]);
            o.chart = new google.visualization.LineChart(document.getElementById(o.target));
          }

          o.chart.draw(o.data, o.options);
        }
      }

      function animateRenewal(option){
        var o = option;
        if (o.data.getNumberOfRows() >= 10) {
          o.data.removeRow(0);
        }


        var value = 0;
        var maxValue = o.options.vAxis.maxValue;
        if(maxValue <= 1){
          value = Number((Math.random() * maxValue).toFixed(1));
        }else {
          value = Math.floor(Math.random() * maxValue);
        }
        o.data.insertRows(o.data.getNumberOfRows(), [[getNowTime(), value]]);
        drawChart(o);
      }

      setInterval(function(){
        animateRenewal(new_option);
      }, 1000);
      
      function getNowTime(){
        var d = new Date();
        var sep = ":";
        var hh = d.getHours();
        var mm = d.getMinutes();
        var ss = d.getSeconds();
        return hh + sep + mm + sep + ss;
      }
      
    </script>
  </body>
</html>

 

동작캡처

 

 

 

 


간단하게 코드 동작 설명을 하겠습니다. 해당 소스들은 구글차트 API 공식 문서가 아니며 제가 사용하기 위해 만든 코드입니다.

 

구글차트를 사용하기 위해 loader.js를 연결하였고 , 아래 2줄부분은 차트를 세팅하고  준비가되면 drawChart 함수에 의해 차트를 그립니다.

<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> //구글차트 사용을 위해 loader.js 추가
<script type="text/javascript">
    //Google Stuff
    google.charts.load('current', {packages: ['corechart']});
    google.charts.setOnLoadCallback(function(){ drawChart(new_option)});
</script>

 

 

다음으로 drawChart메소드에 사용된 new_option은 chartOption 생성자를 통해 클래스기반의 구글차트에서 사용할 데이터입니다.

1. @param >target : 차트를 그릴 요소의 ID값입니다.

2. @param >maxValue : 차트의 Y축 데이터의 맥스값입니다.

3. @param >color: 차트를 그릴때 사용할 색상입니다.

4. @param >name: 차트의 이름을 만들용도로 사용했습니다.

var chartOption = function(target, maxValue, color, name){
  this.name = name;
  this.target = target;
  this.data = null;
  this.chart = null;
  this.options = {
    legend: { position: 'none' },
    vAxis: {minValue:0, maxValue:maxValue},
    hAxis: {
      textStyle: {
        fontSize: 11
      }
    },
    colors: [color],
    animation: {
      duration: 500,
      easing: 'in',
      startup: true
    }
  }
  
}

var new_option = new chartOption('chart', 80, '#FF5E00', '온도');

객체 내부의 chart, options, data부분은 구글차트의 데이터를 집어넣기 위해 사용했습니다.

 

 

다음으로 drawChart 함수를 보겠습니다.

function drawChart(option) {
  var o = option;
  if(o != null){
    //초기값일때만 처리
    if(o.chart == null && o.data == null){
      o.data = new google.visualization.DataTable();
      o.data.addColumn('string', 'time');
      o.data.addColumn('number', o.name);
      o.data.addRow(['', 0]);
      o.chart = new google.visualization.LineChart(document.getElementById(o.target));
    }

    o.chart.draw(o.data, o.options);
  }
}

처음 객체의 chart, data속성을 확인하고 null이라면 처음 new로 생성된 객체이므로 초기값 세팅을 해줍니다.

이부분에서 그릴 데이터의 옵션, 초기값들을 설정하면서 제목과 그리는 차트이름을 설정합니다.

저는 LineChart를 사용했습니다.

처음만 초기값부분을 타고 이후에는 chart.draw동작만 처리합니다.

 

 

마지막으로 볼 부분은 animateRenewal함수입니다.

function animateRenewal(option){
  var o = option;
  if (o.data.getNumberOfRows() >= 10) {
    o.data.removeRow(0);
  }


  var value = 0;
  var maxValue = o.options.vAxis.maxValue;
  if(maxValue <= 1){
    value = Number((Math.random() * maxValue).toFixed(1));
  }else {
    value = Math.floor(Math.random() * maxValue);
  }
  o.data.insertRows(o.data.getNumberOfRows(), [[getNowTime(), value]]);
  drawChart(o);
}

setInterval(function(){
  animateRenewal(new_option);
}, 1000);

해당 함수에는 일정시간마다 반복하면서 데이터를 만들기 위해 만들었습니다.

실제 DB데이터에서 데이터를 가져와서 넣을분들은 이부분을 ajax 비동기처리하여 값을 가져오시고 마지막에 처리한 data.insertRows()메소드, data.removeRow()후 drawChart를 사용하시면 됩니다.

 

insertRows 메소드에 대해 간단히 설명드리면

첫번째 파라미터에 현재 구글차트에 들어간 데이터에 넣을 위치(index)값이며,

두번째 파라미터는 처리할 값입니다. 0번째값은 표기할 값 1번째값은 실제 값입니다. ex) 15:40:30  34도

 

removeRow 메소드는 입력하신 index값의 데이터를 지워줍니다.

저는 제일 과거의 데이터만 삭제하기 위해 0만 지워주도록 했습니다.

 

setInterval 메소드를 1초마다 동작시켜서 1초마다 랜덤함수로 데이터를 가져와 animateRenewal함수를 계속 동작시켜서 계속 그리도록 처리하였습니다.

반응형
반응형

바쁘신분들을 위해...

chrome, IE 모두 new Date를 사용하려면 replace 정규식을 활용하여

-, .등으로 구분된 날짜값을 /으로 변경처리한다.

var timedate = "2020-01-31 13:46:55";
new Date(timedate.replace(/[.-]/gi, "/")); //정상동작
//"2020/01/31 13:46:55";

air datepicker 라이브러리를 활용하여 달력을 제어할 일이 있었는데, 여기서 날짜등을 제한할때,

new Date() 메소드를 활용하여 특정 프로퍼티에 넣어주면 제한이 되었다.

 

년월일까지만 있는 경우에는 전혀 문제없이 달력이 동작하였는데,

어느날 버그 신고가 있어 확인해보니 제한 날짜를 입력해주는 부분이

(yyyy-MM-dd HH:mm:ss) 형태였다.

 

 

new Date 사용예시

IE와 크롬에서 결과값을 콘솔에 찍은 사진인데 날짜형태의 yyyy-MM-dd는 문제가 없다.

var str_date = "2020-01-31";
console.log(new Date(str_date));

 

 

 

 

날짜 "." 구분자

하지만 "."구분자는 문제가 있다.

var str_date = "2020.01.31";
console.log(new Date(str_date));

 

IE에서 표준이 아닌듯하다... 인식하지 못한다.

 

 

 

날짜 시간의 구분자 "-"

먼저 사용예제로 보여주었다 "-" 구분자도 시분초까지 있는 경우 문제가 발생한다.

var str_date = "2020-01-31 13:51:55";
console.log(new Date(str_date));

 

크롬은 언제나 잘 동작한다... 크롬짱

 

구분자 "/"

그럼 크롬과 IE에서 모두 동작하려면 어떻게 해야할까?

바로 구분자를 "/"으로 날짜부분을 처리하면 된다.

var str_date = "2020/01/31 13:51:55";
console.log(new Date(str_date));

 

"2020/01/31 13:51:55" new Date() 결과

 

 

 

정규식을 통한 크로스 브라우징

보통 날짜부분은 "-", ".", "/" 으로 구분을 많이 하는데 모두 동작하게 하려면, 정규식을 사용하면 된다.

var str_date = "2020-01-31 13:51:55"; //"2020.01.31 13:51:55" 
str_date = str_date.replace(/[.-]/gi, "/") //. 또는 -으로 되어있는 부분을 치환한다.
console.log(new Date(str_date));

 

.구분자 -구분자 모두 replace 시켜서 두 브라우저 모두 동작한다.

반응형
반응형

Object는 key, value로 구성된 객체인데, 이 Object가 배열안에 n개로 들어있고, key값이 어떻게 되어있는지 모를때 차례대로 특정 key를 구하고 key에 해당하는 value값을 구하는 예제를 보겠습니다.

 

숫자로 들어갈 값은 랜덤함수로 처리하였습니다.

var arr = [];
for(i=1; i<11; i++){
  var keyName = "count"+i
  var count = Math.floor(Math.random()*1000);
  var obj = new Object();
  obj[keyName] = count;
  arr.push(obj);
}

arr.forEach(function(value){
  console.log(value);
});

 

해당 소스가 있다고 가정하고 콘솔창을 확인해보면, 아래 그림처럼 한줄씩 객체 데이터가 표현되는걸 볼 수 있습니다.

여기서 각각 해당 Object값의 키 값을 구하고 그 키를 활용하여 value값을 출력해보겠습니다.

forEach문을 통해 출력

 

Object.keys();

Object.keys(obj); //parameter의 obj는 key를 찾고자 하는 Object

Object.keys 메소드를 활용하면 현재 Object의 key값들을 보여주는데, 메소드를 통해 구하고 각각의 value값을 출력하면 됩니다.

 

출력 예제

arr.forEach(function(value){
  var obj_key = Object.keys(value); //key를구하고
  var obj_value = value[obj_key]; //key를 활용하여 value값을 구한다.
  console.log(obj_key + " : " + obj_value); //출력
});

출력결과

아까와는 다르게 Object형으로 찍히는게 아닌 String형태로 찍힌 결과를 볼 수 있습니다.

반응형
반응형
<form>
    <input type="text" name="user_name">
    <button id="save">저장</button>
</form>

과 같은 코드가 있을때 jquery를 활용하여

 

아래처럼 클릭이벤트에 따른 ajax동작을 정의하고, 비동기처리를 하려고 한다.

$("#save").click(function(){
 ...ajax 동작
})

ajax에서는 user_name값을 파라미터로 가지고 컨트롤러로 넘겨서 DB에 저장하는 로직을 구성하였는데,

컨트롤러에 요청이 2번씩 가는 현상을 한번씩 볼 수 있다.

 

form태그 내부의 button이 default동작인 submit으로 동작하면서 form동작 + ajax동작이 동시에 일어났기 때문이다.

 

가장 간단한 해결책은 button을 submit이 아닌 button이라고 지정을 해주는 것이다.

 


type="button" 지정하기

<button type="button" id="save">저장</button>

 


 

또는 form태그 내부의 모든 버튼이 submit 동작을 하지 않도록 form태그에 속성을 추가하면 된다.

form태그 자동 submit 끄기 (autocomplete="off")

<form autocomplete="off">
   ...
</form>
반응형
반응형

Rest properties

ES6문법으로 객체나 배열에 값을 할당할 때 사용한다.

const info={
    id: 0,
    name: "홍길동",
    phone: "010-1234-1234"
}

const {id, ...newInfo} = info;
//const id에는 0이 들어가고 나머지는 newInfo 객체에 할당된다.
id; //0
newInfo //{name: "홍길동", phone: "010-1234-1234"}

 

 

Spread properties

ES6문법으로 새로운 객체에 자체적으로 열거한 속성을 할당한다.

let n = {id, ...newInfo};
n; //{id: 0, name: "홍길동", phone: "010-1234-1234"}

 

활용 예시)

배열 특정 데이터 삭제하기 - 1~5까지 존재하는 배열에서 3만 삭제하기

const arr = [1,2,3,4,5];

const newArr = arr.slice(0,2).concat(arr.slice(3,5));

slice 메소드를 활용하여 잘라내고, concat 메소드를 통해 잘라낸 부분을 다시 합치는 방법입니다.

 

 

하지만 Spread properties 방식을 사용하면 아래처럼 구현이 가능합니다.

const newArr2 = [...arr.slice(0,2), ...arr.slice(3,5)]

 

값 추가도 굉장히 쉽게 할 수 있습니다.

const numberArr = [...arr, 6, 7, 8, 9, 10];
numberArr; //1, 2, 3, 4, 5, 6, 7, 8, 9, 10

let temp = [5, 6, 7, 8, 9, 10];
const numberArr2 = [...arr, ...temp];

numberArr2 //1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10

 

반응형