티스토리 뷰

HTML로 카드 만들기 - 1

구현하고자 하는 것

  • 구현 기능
    • 카드의 배경색 및 테두리색 지정
    • 카드에 스티커 추가(드래그 앤 드롭 기능)
      • 스티커 크기 선택 가능(S,M,L)
      • Canvas API 사용
    • 카드에 메세지 추가
      • 컬러 및 폰트 크기 변경 가능
    • 카드 세이브 및 읽어오기 기능
    • 카드 지우기(백지화) 기능
  • Further Issues
    • UI :) ...
    • 전체 지우기 기능 말고, 바로 직전의 행동 삭제하는 기능 추가

기능별 Code

  • 전체 코드
  • 카드의 배경색 및 테두리색 지정
    // javascript
    var bgBtn = document.getElementById("bgBtn");
    var brBtn = document.getElementById("brBtn");
    var canvas =
    document.getElementById("canvas");
    var ctx = canvas.getContext('2d');
    
    // background color change
    function backgroundChange() {
        ctx.fillStyle = bgBtn.value;
        ctx.fillRect(1,1,canvas.width-2, canvas.height-2);
    }
            
    // border color change
    function borderChange() {
        canvas.style.border = "none";
        ctx.strokeStyle = brBtn.value;
        ctx.strokeRect(0,0, canvas.width, canvas.height);
    }
    
    • type이 color인 input태그를 생성하여 컬러를 선택할 수 있도록 한다. 선택된 값들은 나중에 Element.value로 가져올 수 있다.
    • input 태그에 onclick 이벤트를 추가했고, script 영역에 해당하는 함수를 작성한다.
    • script 영역에는 돔객체들을 가져다 쓸 수 있도록 변수 선언을 상단에 해준다.
    • 함수 내부에는 canvas API의 문법이 사용되었는데, 테두리(stroke)를 그리거나 컬러를 채우는 등(fill) 간단한 기능을 사용하였다.
  • <!--body--> 배경 컬러 설정 : <input type="color" id="bgBtn" onchange="backgroundChange()"> 테두리 컬러 설정 : <input type="color" id="brBtn" onchange="borderChange()"> <!--canvas, stickerBox--> <section> <div id ="mycard"> <canvas id="canvas" width="600px" height="600px"></canvas> </div> <div id="sticker"> </div> </section>
  • 이미지 드래그 앤 드롭
    // javascript
    var mycard = document.getElementById("mycard");
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext('2d');
    
    //append imgs
    for(var i = 1 ; i <= 40 ; i++) {
        var img = document.createElement("img");
        img.src = `../kakao/g${i}.png`;
        document.getElementById("sticker").appendChild(img);
    }  
    
    // drag and drop
    function load() {
        var imgs = document.querySelectorAll('img');
        for(var i = 0 ; i < imgs.length ; i++) {
            imgs[i].setAttribute('draggable',true);
            imgs[i].setAttribute('id', `img${i+1}`)
            imgs[i].addEventListener('dragstart', drag);
        }
        canvas.ondragover = function(e) {
            e.preventDefault();
        }
        canvas.addEventListener('drop', drop);
    }
    
    function drag(e){
        e.dataTransfer.setData('data', e.target.id);
        e.dataTransfer.setDragImage(e.target, 0, 0);
    }
    
    function drop(e) {
        e.preventDefault();
        var id=e.dataTransfer.getData('data');
        var el=document.getElementById(id);
        var posx=e.pageX-this.offsetLeft; // this === e.target
        var posy=e.pageY-this.offsetTop;
        // checked radio button 
        for(var i = 0 ; i < radio.length ; i++) {
            if(radio[0].checked === true) {
                //small
                ctx.drawImage(el, posx-el.width/2+10 , posy-el.height/2+10, el.width * 3/4, el.height * 3/4);
            } else if(radio[1].checked === true) {
                //medium
                ctx.drawImage(el, posx-el.width/2 , posy-el.height/2, el.width *1.1, el.height*1.1);
            } else if(radio[2].checked === true) {
                //big
                ctx.drawImage(el, posx-el.width/2 , posy-el.height/2, el.width * 1.5, el.height *1.5);
            }
        }
    }
    
    window.addEventListener('load', load, false);
    
    • 이미지 추가
      • sticker 박스에다가 스티커를 렌더링하고, 이를 드래그해서 캔버스에 드롭할 수 있도록 해야한다. 그러기 위해선 먼저 sticker div영역에 스티커 이미지들을 append해서 보여줘야 한다.
      • createElement('img') 를 사용하여 이미지 돔 객체를 만든다. 그 다음 소스를 부여하고, 이를 보여주고자 하는 위치(sticker div)에 append한다.
      • 여러 개의 이미지를 추가하기 위해 for문을 사용하였다. 이를 위해서는 이미지 소스가 일관적인 숫자를 포함하여야 한다. 위 코드의 경우 이미지명을 g1, g2, g3... 이런 식으로 설정하여 for문으로 소스 부여를 처리하기 쉽게 하였다.
    • 드래그 앤 드롭
      • HTML의 drag and drop API를 사용하였다. 참고: MDN 문서, html5rocks.com
      • dragstart, dragover, drop 순으로 이어진다. 이 세가지 중 하나가 제대로 되지 않으면 다음 함수가 제대로 작동하지 않는다.
      • 우선 drag될 대상(이미지들)에 dragstart 이벤트를 추가한다. 이미지가 여러 개이기 때문에 역시 for문을 사용했다. querySelectorAll로 HTMLCollection을 불러온 뒤, for문으로 돌면서 속성을 부여했다.
      • 각 이미지 객체에 draggable 속성을 추가하고, id 지정, dragstart 이벤트 추가를 하였다. 여기서 id는 반드시 지정해야 하는데, 그 이유는 뒤에 dataTransfer을 사용하기 때문이다. 드래그 앤 드롭 시 데이터를 전달할 수 있는 이 API를 사용하기 위해서는 객체의 고유한 id가 있어야 한다. dataTransfer을 사용하는데 객체에 id 속성이 없으면 데이터 전달이 이루어지지 않아 null을 리턴한다. (처음에 지정해주지 않아 뒤에서 cannot read property width of null 에러가 났었다)
      • dragstart 이벤트를 추가한 뒤 이번엔 드롭할 영역에 dragover, drop 이벤트를 설정한다. 이 예제에서는 canvas 영역에 드롭할 것이므로 canvas에 이벤트를 추가한다. addEventListener로 추가할 때랑 돔객체에 . 찍고 추가할 때에 효과는 같은데 이벤트명에 차이가 있다. 흔하게 on의 유무가 다르다.
      • 여기서 내가 이유도 모르고 계속 에러가 났던 부분은 e.preventDefault(); 이다. e.preventDefault는 해당 이벤트(여기서는 dragover, drop) 외에 별도의 브라우저 행동을 막기 위해 사용된다. 이 함수는, dragstart에는 사용하면 안 되고 dragover과 drop에는 사용해야만 한다.
        • 함수명에서 알 수 있듯이 이 함수는 default 행동을 막기 위한 것이다. div내에서는 default 행동이 drop하지 않는 것이기 때문에, dragover이벤트 함수에서 preventDefault 함수를 호출하여 디폴트 행동을 취소하지 않으면 drop이벤트가 실행되지 않는다. (In order to allow a drag-and-drop action on a div, must cancel the default action)
        • 또한 drop이벤트 함수 내에서 이를 사용하지 않으면 drop하려는 파일을 브라우저가 실행해버리기 때문에 사용해야 한다.
        • 다만 처음에 실수로 dragstart이벤트 함수 내에도 preventDefault함수를 호출하는 바람에, dragover 이벤트가 실행되지 않았다. dragstart에서 이를 호출하면 이벤트가 취소돼 버린다.
      • drag이벤트 함수 내에는 dataTransfer함수를 사용해서 데이터를 전달할 수 있도록 했다. 이를 사용해서 문자열, 파일 등 다양한 객체를 전달할 수 있지만 여기서는 간단하게 돔 객체만 grab하면 되므로 id를 통해 전달했다. (dataTransfer의 첫번째 param은 아무 문자열을 넣어도 상관없는 듯하다)
      • 이렇게 전달된 객체를 선택자로 선택하여 drop이벤트함수에서 전달받은 다음 canvas API를 사용해서 drop된 위치에다가 객체를 그리면 된다. (drawImage 함수 사용) 나는 라디오버튼을 통해 이미지 사이즈를 선택할 수 있게 만들었고, 체크된 항목을 grab하여 조건문을 써서 그려지는 이미지 크기를 다르게 설정했다.
      • 페이지가 모두 로드된 다음에 이 함수들을 실행해야 에러가 안 나기 때문에(예를 들어 이미지도 로드가 안됐는데 드래그앤드롭을 실행하려고 하면 당연히 에러가 난다) window onload 함수를 사용했다.
  • <!--canvas, stickerBox--> <section> <div id ="mycard"> <canvas id="canvas" width="600px" height="600px"></canvas> </div> <div id="sticker"> </div> </section>

 

'공부일지(TIL) > Others' 카테고리의 다른 글

하드웨어의 한계  (0) 2021.01.22
컴퓨팅 사고 - 이진법  (0) 2020.12.23
Design Patterns Intro  (0) 2019.05.17
Node File System Module  (0) 2019.04.28
Functional Programming 3  (0) 2019.03.18
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함