[정보] IT정보&활용 2024. 8. 27. 13:14

[구글 스프레드 시트] 서명받기

반응형

http://swsp.or.kr/3.html

 

appsscript활용

4 대상자 검색,수정,추가하기1 동영상 대상자 검색,수정,추가하기2 동영상 대상자 검색,수정,추가하기3 동영상 대상자 검색,수정,추가하기4 동영상 대상자 검색,수정,추가하기5 동영상 대상자 검

swsp.or.kr

여기에 가보면 구글 스프레드 시트 의 앱 스크립트를 활용한 다양한 사례들을 보여주고 있다.

그 중 주목한 것 하나가 바로 "서명받기"

후원신청서나 프로그램 참가 신청을 받을 때에도 유용할 거 같아서 좀더 자세히 살펴보았다.

소스는 다 오픈되어 있어 하나하나 뜯어보면서 나에게 필요한 방식으로 수정해보았다.

 

https://script.google.com/a/macros/bmsenior.org/s/AKfycbyU6cbIQfPkMm9Soqcz5l9ORI_QB320vAogSsqQFnGYoLEVxM118wXig9rsB32ogHc/exec

여기에 입력하면, 

 

https://docs.google.com/spreadsheets/d/13EJTaSd31_r8A8I4v6WzGqr1BJfqsmVmu4Xv55IpZpw/edit?gid=0#gid=0

여기에 이름과, 서명이미지, 그리고 해당 이미지의 url을 저장해 보여준다.

 

그런데 이 걸 내가 사용하기 위해서는 몇가지 수정해야할 것이이 있다.

서명이 저장되는 ① 구글 스프레드 시트의 고유 ID를 알아야하고, ② 서명 이미지가 저장될 폴더의 고유 ID를 알아야 한다.

마지막으로 ③ 저장될 시트의 이름도 일치시켜야 한다.

 

그래서 내가 편하려고 소스를 좀 수정해보았다.

 

1. Code.gs 

function doGet() {
  return HtmlService.createTemplateFromFile("index").evaluate();
}

function receiveSiganture(encodedImage,signame){

  // 폴더, 스프레드시트 ID 및 시트명을 직접 입력해주세요.
  const folderId = "23GF3aHMo0MDOxjCQLss12Ir-WjQmQT_T7B9";
  const spreadsheetId = "2Ak0WTqcdsc25RcaQZ86dRNMbddcOn88_eIdo";
  const sheetName = "시트1";

  var fileTime = new Date();
  var s1 = signame.sigName;
  const data = encodedImage.split(",")[1];
  const dataDecoded = Utilities.base64Decode(data);
  const signatureAsPictureBlob = Utilities.newBlob(dataDecoded).setName(s1+fileTime+"somefile.png");

  // 서명이 저장될 폴더
  var signurl = DriveApp.getFolderById(folderId).createFile(signatureAsPictureBlob).getId();
  var signfile = '=image("https://drive.google.com/uc?export=view&id=' + signurl + '")';
  var signfile2 = "https://drive.google.com/drive/folders/" + folderId + "/uc?export=view&id=" + signurl;
 
  // 입력된 서명 정보가 저장될 스프레드 시트
  var sa = SpreadsheetApp.openById(spreadsheetId);
  var sheet1 = sa.getSheetByName(sheetName);
  var rowData = [[fileTime, s1, signfile, signfile2]];
  var lastRow = sheet1.getLastRow();

  sheet1.getRange(lastRow+1, 1, 1, 4).setValues(rowData);
  getTexttS();
 
}

function getTexttS(form){
       var text = "서명이 입력되었습니다.";
       return text;
}

이제 위 음영처리한 ID와 이름만 정확히 확인해서 입력하면, 다른 소스는 수정할 필요가 없다.

 

2. index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>서명받기</title>
  </head>
  <body>
    <form id="signatureForm">
     
      <div id="app" class="container">
        &nbsp;<h2>성함을 입력하시고 아래 패드에 서명해 주세요.</h2><br><br>
        &nbsp;성명: <input type="text" name="mname" id="mname"><br><br>
        <div class="">
        <canvas id="sig" style="background-color: #e0e0e0; border: 1px solid black; width: 500px height: 300px;">
        </canvas>
        </div>
        <div>
          <button type="button" id="clearSig">Clear</button>
          <button type="button" id="send">Send</button>
        </div>
       
      </div>
      <input type="hidden" id="mtext" name="mtext">
    </form>
    <!-- 서명패드 스크립트: 오픈소스이며, 무료입니다. 아래는 원본 링크 -->
    <script>

      var signaturePad

      function setupSignatureBox(){
       
        var canvas = document.getElementById("sig");
        signaturePad = new SignaturePad(canvas);
      }

      function clearSignature(){
        signaturePad.clear();
      }

      function sendToDrive(){
        if(mname.value.length == 0){
          alert("성명을 입력하세요");
          mname.focus();
        } else {
        var imageData = signaturePad.toDataURL();
        var signame = {sigName: document.getElementsByName('mname')[0].value};
        google.script.run.receiveSiganture(imageData, signame);
        google.script.run.withSuccessHandler(getText).getTexttS(document.forms[0]);
        setTimeout('note()', 2000);
        clearSignature()
        // console.log(imageData);
        }
      }

      function note(){
        var alt = document.getElementById('mtext').value;
        alert(alt);
        document.getElementById("signatureForm").reset();
      }

      function getText(text){
        var txtTextt = document.getElementById('mtext');
        txtTextt.value = text;
      }

      document.getElementById("clearSig").addEventListener("click",clearSignature);
      document.getElementById("send").addEventListener("click",sendToDrive);
      document.addEventListener("DOMContentLoaded",setupSignatureBox);
    </script>

  </body>
</html>

원본에서는 1개의 css 파일과 2개의 js 파일을 참조토록 하고 있었다.

하지만 굳이 디자인이 복잡할 필요가 있는게 아니라서 과감히 삭제했다.

그리고 꼭 필요한 서명용 js 파일을 확인하고, 원본 사이트에 들어가 가장 최신의 스크립트로 교체하였다.

 

github에서 배포되고 있으며, 확인결과 상업적 사용까지 무료인 것을 확인하였다.

https://github.com/szimek/signature_pad

 

GitHub - szimek/signature_pad: HTML5 canvas based smooth signature drawing

HTML5 canvas based smooth signature drawing. Contribute to szimek/signature_pad development by creating an account on GitHub.

github.com

그리고 이를 웹에서 링크로 사용할 수 있도록 제공하는 url은 위와 같다.

 

사실 gemini에게 물어보면 굳이 링크에 있는 스크립트를 사용하지 않아도 이미지를 그릴 수 있는 소스를 만들어준다.

 

1. Code.gs

// 그리기 기능
function doGet() {
  var html = HtmlService.createHtmlOutputFromFile('index');
  return html;
}

// 지우개 기능 (선의 색을 흰색으로 설정)
function erase() {
  ctx.strokeStyle = 'white';
  // 드로잉 로직과 동일하게 사용
}

 

2. index.html

<!DOCTYPE html>
<html>
<head>
  <base target="_top">
</head>
<body>

    성명: <input type="text" name="ur_name" id="ur_name"><br><br>
    <input type="hidden" id="n_text" name="n_text">
    <canvas id="myCanvas" style="background-color: #e0e0e0; border: 1px solid black; width: 500px height: 300px;"></canvas>
    <button id="saveButton">저장</button>
    <button id="clearButton">지우기</button>

  <script>
    const canvas = document.getElementById('myCanvas');
    const ctx = canvas.getContext('2d');
    let isDrawing = false;
    let lastX = 0;
    let lastY = 0;

  function startDrawing(e) {
    isDrawing = true;
    [lastX, lastY] = [e.offsetX, e.offsetY];
  }

  function draw(e) {
    if (!isDrawing) return;
    ctx.beginPath();
    ctx.moveTo(lastX, lastY);
    ctx.lineTo(e.offsetX, e.offsetY);
    ctx.stroke();
    [lastX, lastY] = [e.offsetX, e.offsetY];
  }

  function stopDrawing() {
    isDrawing = false;
  }

  canvas.addEventListener('mousedown', startDrawing);
  canvas.addEventListener('mousemove', draw);
  canvas.addEventListener('mouseup', stopDrawing);
  canvas.addEventListener('mouseout', stopDrawing);

  // 터치 이벤트 추가 (모바일 지원)
  canvas.addEventListener('touchstart', startDrawing);
  canvas.addEventListener('touchmove', draw);
  canvas.addEventListener('touchend', stopDrawing);

  // 지우기 버튼 클릭 이벤트 처리
  const clearButton = document.getElementById('clearButton');
 
  clearButton.addEventListener('click', () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  });

  </script>
</body>
</html>

 

처음의 드로잉처럼 자연스럽진 않지만, 그래도 웬만큼 흉내는 된다.

이걸 다시 세세한 부분을 손봐야하는데, 귀찮아서... ㅡ.ㅡ

반응형