IT기타

태블릿(모바일)용 크롬 확장프로그램 개발(스크롤, touch처리, html5, canvas)

emilyyoo 2025. 1. 25. 14:03
728x90

 
 
 

개발 목적

태블릿의 웹페이지 위에서 드로잉하기

 

계기

예전에 웹사이트 구축이 많지 않았던 시절, 종이로만 긴 글이나 신문기사를 읽는게 당연했다. 그때, 나는 중요 부분에 밑줄을 긋거나 동그라미를 치면서 읽었다.

이제 모든 것이 온라인으로 전환되었지만 여전히 글만 보면 빨간, 파란 펜으로 밑줄 치고 체크하고 메모하고 싶다.

웹에서 이렇게 하려고 몇 개 확장 프로그램도 깔아보고 앱도 찾아봤지만 딱 내가 원하는 게 없다. 그래서 직접 만들어봤다.

 

개발 과정

 

1. 기본: 드로잉 캔버스 구현

웹페이지의 DOM 위에 <canvas> 요소를 추가하여 드로잉 기능을 구현했다. 사용자가 터치나 마우스 입력을 통해 그림을 그릴 수 있도록 이벤트 리스너를 설정했다.

javascript
function enableDrawingMode() { 
  if (!canvas) { 
    canvas = document.createElement("canvas"); 
    canvas.style.position = "fixed"; 
    canvas.style.top = 0; 
    canvas.style.left = 0; 
    canvas.style.zIndex = 10000; 
    canvas.width = window.innerWidth; 
    canvas.height = window.innerHeight; 
    canvas.style.pointerEvents = "none"; 
    document.body.appendChild(canvas); 
 
    context = canvas.getContext("2d"); 
    context.strokeStyle = "red"; 
    context.lineWidth = 2; 
 
    window.addEventListener("touchstart", handleTouchStart); 
    window.addEventListener("touchmove", handleTouchMove); 
    window.addEventListener("touchend", handleTouchEnd); 
  } 
}

 

===> 기본적인 드로잉 기능 자체는 캔버스를 이용해서 하니깐 단순했다.

하지만 난 진짜 종이로 글읽듯이 화면을 스크롤 하면서 글 중간중간 펜으로 표시를 하고 끝까지 다 읽었을 때 다시 위로 올라가도 그 표시가 계속 남아 있는 걸 원했다.

 

이럴 때 구현에 어려움이 나타났다.

그림을 그리고 난 후에는 스크롤이 안된다거나

기존 웹페이지의 동작들을 다 막는 현상이 나타난다거나,

터치를 하며 그림을 그릴 때 화면도 같이 움직인다던가 등등..

 

하나를 고치면 또 다른 문제가 발생하는 전형적인 프로그래밍의 특징이 나타났다.

 

2. 팝업창 오류와 메시지 통신 문제

문제: 확장프로그램의 팝업창에 프로그램을 실행하는 버튼을 만들었는데, 버튼을 눌렀을 때 다음과 같은 오류가 발생했다.

 

The message port closed before a response was received.

 

원인 : 브라우저 확장 프로그램에서 팝업창과 콘텐츠 스크립트 간 메시지 통신 구조의 비동기 처리와 관련된 문제였다. 메시지 리스너가 비동기 작업임을 명확히 하지 않아서, 메시지가 제대로 처리되기 전에 연결이 닫혔다.

 

 

해결: 메시지 리스너에 return true를 추가해 비동기 작업임을 명시했다. 메시지 통신의 비동기 처리가 끝나기 전에 연결이 닫히지 않도록 했다.

 

javascript
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { 
    if (message.action === "toggleDrawing") { 
        toggleDrawingMode(message.enabled); 
        sendResponse({ success: true, message: `Drawing mode ${message.enabled ? "enabled" : "disabled"}` }); 
    } else { 
        sendResponse({ success: false, message: "Unknown action" }); 
    } 
    return true; // 비동기 응답 처리 
});

 

3. 스크롤이 안됨

 

문제: 터치가 오직 그림 그리는 것 밖에 안 되고 본래 웹페이지의 기능도 막고 스크롤이 안 된다.

 

원인: 터치 이벤트에서 드로잉 모드가 아닌 경우의 처리가 없음.

 

해결: 드로잉 모드와 터치 모드를 구분하는 제스처를 추가하고, 그것을 저장하는 변수로 터치이벤트 로직을 처리했다.

 

javascript
// 터치 이벤트 처리
canvas.addEventListener("touchstart", (e) => { 
    if (scrollMode) return; // 스크롤 모드일 때는 드로잉 비활성화
    isDrawing = true; 
    const touch = e.touches[0]; 
    lastX = touch.clientX; 
    lastY = touch.clientY; 
});

canvas.addEventListener("touchmove", (e) => { 
    if (!isDrawing) return;
    // 드로잉 모드일 때 기본 스크롤 방지
    e.preventDefault();
    // 기타 드로잉 로직...
});

 

4. 터치를 하며 그림을 그릴 때 화면도 같이 움직인다.

 

해결: "touchmove" 이벤트에서 드로잉 모드일 때, 스크롤 안 되게 설정

 

javascript
e.preventDefault(); // 기본 스크롤 방지

 

5. 스크롤과 그림 동기화 문제

 

문제: 페이지를 스크롤하면 그렸던 그림은 스크롤되지 않고 고정된 위치에 그대로 있어서 엉뚱한 위치에 보이게 된다.

 

원인: 캔버스의 style.top과 style.left 속성을 스크롤 값에 동기화하지 않았기 때문.

 

해결: 두 가지 방법이 있다:

  1. 캔버스를 정적으로 유지하고, 스크롤 위치에 맞춰 그림을 다시 그린다.
  2. 캔버스 요소 자체를 스크롤 위치에 맞게 이동시킨다.

첫 번째 방법 : 캔버스 자체를 이동시키는 대신, 저장된 그림들을 다시 그리면서 스크롤 위치에 맞추어 조정한다. 이 방법으로 하면 캔버스를 초기화 할때 위치 옵션을 "fixed"로 해줘야 한다.  

 

javascript
function setupCanvas() { 
    canvas.style.position = "fixed";  // 캔버스를 고정 위치로 설정
    canvas.style.top = "0"; 
    canvas.style.left = "0"; 
    canvas.style.zIndex = "9999"; 
    canvas.style.pointerEvents = "none"; // 초기엔 비활성화
}

function redrawCanvas() { 
  // 캔버스를 깨끗하게 지우기 
  ctx.clearRect(0, 0, canvas.width, canvas.height); 

  // drawings 배열을 반복하여 각 그림 다시 그리기
  drawings.forEach(drawing => { 
    // 새로운 경로 시작
    ctx.beginPath(); 

    // 스크롤 위치에 맞춰 시작 좌표로 이동
    ctx.moveTo(drawing.startX - window.scrollX, drawing.startY - window.scrollY);

    // 스크롤 위치에 맞춰 끝 좌표로 선 그리기
    ctx.lineTo(drawing.endX - window.scrollX, drawing.endY - window.scrollY); 

    // 선 스타일 설정
    ctx.strokeStyle = 'red'; 
    ctx.lineWidth = 2; 

    // 선 그리기
    ctx.stroke(); 
  });
}

// 스크롤할 때마다 캔버스를 다시 그리도록 이벤트 리스너 추가
window.addEventListener('scroll', redrawCanvas); 

// 페이지가 처음 로드될 때 한 번 캔버스를 그리기
redrawCanvas();

 

 

두 번째 방법 : 스크롤 이벤트를 감지하여 캔버스 위치를 업데이트하는 코드를 추가했다. 또한, 스크롤과 함께 캔버스가 이동하도록 translate 적용. 이때는 canvas.style.position = "absolute"; 로 초기설정을 해서 웹페이지를 기준으로 배치하도록 한다. 

 

javascript
const updateCanvasPosition = () => { 
  const scrollX = window.scrollX; 
  const scrollY = window.scrollY; 
  canvas.style.transform = `translate(${scrollX}px, ${scrollY}px)`; 
}; 
window.addEventListener('scroll', updateCanvasPosition);

 

6. 스크롤 후 터치지점과 그림의 좌표가 어긋나는 문제.  

 

문제: 스크롤 후 다시 그림을 그리려고 하면, 그림 좌표가 잘못 계산되었다.

 

원인: 터치 좌표를 계산할 때 스크롤 값을 포함하지 않았기 때문에, 좌표가 어긋났다.

 

해결: 터치 이벤트에서 좌표를 clientX, clientY로 설정 (위에서 첫번째 방법을 선택한 경우)

 

 
javascript
canvas.addEventListener("touchstart", (e) => { 
    const touch = e.touches[0]; 
    lastX = touch.clientX; 
    lastY = touch.clientY; 
});

 

7. 멀티터치 처리와 한 손가락 터치에 따라 다른 처리

 

하려는 것 : 한손가락 터치일 경우에만 그리기 가능하고, 두손가락 이상 터치일 경우에는 그리기 기능안되고 대신 스크롤이 되는 것.

 

문제: 두 손가락으로 터치한 후, 다시 한 손가락으로 그림을 그리려고 하면 그리기 기능이 작동하지 않았다.

 

원인: 멀티터치 이벤트가 감지된 상태에서 그리기 상태를 초기화하지 않아 발생했다.

 

해결: 두 손가락 이상의 터치가 감지되면 isDrawing을 false로 설정하고, 다시 한 손가락 터치 시 정상적으로 초기화되도록 수정

 

 

canvas.addEventListener("touchstart", (e) => { 
    activeTouches = e.touches.length; 
    if (activeTouches === 1) { 
        isDrawing = true; 
        const touch = e.touches[0]; 
        lastX = touch.clientX; 
        lastY = touch.clientY; 
    } else { 
        isDrawing = false; // 멀티터치 시 그리기 비활성화
    } 
}); 

canvas.addEventListener("touchend", () => { 
    activeTouches = 0; 
    isDrawing = false; // 터치 종료 시 그리기 비활성화
});

 

8. 창 크기 변경 시 캔버스 초기화 문제

 

문제: 브라우저 창 크기를 변경했을 때, 캔버스 크기가 페이지와 동기화되지 않았다.

 

해결:  캔버스 resize 이벤트를 감지하여 캔버스 크기를 동적으로 업데이트하는 코드를 추가했다. 

 

window.addEventListener("resize", () => { 
    canvas.width = document.documentElement.scrollWidth; 
    canvas.height = document.documentElement.scrollHeight; 
});

 

9. 태블릿(모바일)에서 크롬 확장 프로그램 미지원 문제

 

문제: 일반적으로 크롬과 사파리 등 모바일 브라우저는 확장 프로그램을 지원하지 않는다.

 

해결: "Kiwi" 라는 브라우저를 활용하면 모바일에서도 크롬 확장 프로그램을 사용할 수 있다. 이를 통해 태블릿에서도 문제없이 그림을 그릴 수 있도록 했다.

 

10. PC(터치 안 되는 기기)에서 터치스크린 기능을 테스트하기 어려운 문제

 

문제: PC에서는 터치스크린이 없어 태블릿 환경을 테스트하기 어려웠다.

 

해결: PC 크롬 개발자 도구를 활용하여 모바일 환경을 시뮬레이션하면서 테스트를 진행했다. 개발자 도구에서 디바이스 모드를 활성화하여 터치 이벤트를 검증할 수 있었다.

 

F12 → 개발자 도구 → Device Toolbar (Ctrl + Shift + M) → 모바일 기기 선택

 

 

완성 시연 :

 

 

 

마무리

이 프로젝트는 단순한 확장 프로그램처럼 보였지만, 실제 구현 과정에서 터치 이벤트, 스크롤 동기화, 멀티터치 처리 등 다양한 문제를 해결해야 했다.

 

특히 태블릿 환경과 브라우저 확장 프로그램의 특성상 예기치 못한 이슈들이 발생했으며, 이를 해결하는 과정에서 디버깅과 반복적인 테스트가 중요했다.

 

이번 사례는 기기의 특성과 사용자 행동을 고려한 유연한 설계가 얼마나 중요한지를 잘 보여준다.

 

이제 스크롤/드로잉 모드 전환을 좀 더 세련된 방법으로 처리하는 과제가 남았다. 

---->

 

**스트롤/드로잉 모드 전환하는 방법을 개선한 것을 아래 포스팅에 기록했다. 

https://betterwe.tistory.com/306

 

태블릿(모바일)용 크롬 확장프로그램 개발 : 터치펜 입력 감지

태블릿(모바일)용 크롬 확장프로그램 개발ㅇㄴhttps://betterwe.tistory.com/302 태블릿(모바일)용 크롬 확장프로그램 개발(스크롤, touch처리, html5, canvas)개발 목적태블릿의 웹페이지 위에서 드로잉하기

betterwe.tistory.com

 

728x90